概述
前言:作者已进行了优化 ,点击查看详情
提bug记录:https://github.com/bingoogolapple/BGABanner-Android/issues/213
在使用大神(@bingoogolapple)的第三方控件时BGABanner-Android出现的两小个bug记录,issues中也有人遇到过,但无人回复,坐等大神更新,以下为个人处理方案,如有问题请指正。
CSDN:https://blog.csdn.net/lylddingHFFW/article/details/89212664
一 使用场景:使用BGABanner控件,当其宽度较小时,比如只有20dp,这样是很容易滑动到左右边界的。默认ViewPager左右是保留1个Item。
复现bug1:开启无限轮播后,同时手指快速左滑动,一直滑动到viewpager Item不能移动,并松开时,出现anr。(复现概率很大)
复现bug2:开启无限轮播后,同时手指多次快速左滑动,可能出现停止无限轮播现象。(复现几率一般)
二 bug分析及处理方案
1.1 bug1分析:
在BGABanner类代码中,是利用onPageScrolled获取滑动的位置mPageScrollPosition。当ActionUP时在handleAutoPlayActionUpOrCancel中判断左滑还是右滑,来更新滑动位置。
@Override
public void handleAutoPlayActionUpOrCancel(float xVelocity) {
if (mViewPager != null) {
if (mPageScrollPosition < mViewPager.getCurrentItem()) {
// 往右滑
if (xVelocity > VEL_THRESHOLD || (mPageScrollPositionOffset < 0.7f && xVelocity > -VEL_THRESHOLD)) {
mViewPager.setBannerCurrentItemInternal(mPageScrollPosition, true);
} else {
mViewPager.setBannerCurrentItemInternal(mPageScrollPosition + 1, true);
}
} else{
// 往左滑
if (xVelocity < -VEL_THRESHOLD || (mPageScrollPositionOffset > 0.3f && xVelocity < VEL_THRESHOLD)) {
mViewPager.setBannerCurrentItemInternal(mPageScrollPosition + 1, true);
} else {
mViewPager.setBannerCurrentItemInternal(mPageScrollPosition, true);
}
}
}
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
mPageScrollPosition = position;
mPageScrollPositionOffset = positionOffset;
.....
}
滑动现象:获取滑动位置mPageScrollPosition。在滑动过程中onPageScrolled中返回的position,一直是左边Item的位置,这个可以看ViewPager的原理。infoForCurrentScrollPosition返回当前滑动的位置。
因此正常现象如下:
1:只显示当前Item时,mPageScrollPosition = = getCurrentItem();
2:向右滑动时:mPageScrollPosition < getCurrentItem()且mPageScrollPosition +1 = getCurrentItem();
3:向左滑动时:mPageScrollPosition == getCurrentItem();
/**
* @return Info about the page at the current scroll position.
* This can be synthetic for a missing middle page; the 'object' field can be null.
*/
private ItemInfo infoForCurrentScrollPosition() {
final int width = getClientWidth();
final float scrollOffset = width > 0 ? (float) getScrollX() / width : 0;
final float marginOffset = width > 0 ? (float) mPageMargin / width : 0;
int lastPos = -1;
float lastOffset = 0.f;
float lastWidth = 0.f;
boolean first = true;
ItemInfo lastItem = null;
//从左到右遍历
for (int i = 0; i < mItems.size(); i++) {
ItemInfo ii = mItems.get(i);
float offset;
if (!first && ii.position != lastPos + 1) {
// Create a synthetic item for a missing page.
ii = mTempItem;
ii.offset = lastOffset + lastWidth + marginOffset;
ii.position = lastPos + 1;
ii.widthFactor = mAdapter.getPageWidth(ii.position);
i--;
}
offset = ii.offset;
final float leftBound = offset;
final float rightBound = offset + ii.widthFactor + marginOffset;
if (first || scrollOffset >= leftBound) {
if (scrollOffset < rightBound || i == mItems.size() - 1) {
return ii;
}
} else {
return lastItem;
}
first = false;
lastPos = ii.position;
lastOffset = offset;
lastWidth = ii.widthFactor;
lastItem = ii;
}
return lastItem;
}
问题出现: 但是手指快速左滑动,一直滑动到viewpager Item不能移动,并松开时,onPageScrolled中返回的position值又加1了。。。。
log如下:offset==0后手指还处于快速左滑状态。
此时的异常现象 :mPageScrollPosition = getCurrentItem()+1且xVelocity 快速左滑速度超过阈值VEL_THRESHOLD ,代码进入左滑的if()分支,传入的值为mPageScrollPosition + 1 即 getCurrentItem()+2;
那么ViewPager默认是保留左右两个Item的,简单说就是要去找左边第二个没保存Item的position,那么就会一直找不到这Item对应的position(实际上在对比position时,position值由getCurrentItem()+1递减到0,而getCurrentItem()+2不在此范围),由于无限循环次数最大为Integer.MAX_VALUE,执行时间可能超10秒,就报ANR。
mViewPager.setBannerCurrentItemInternal(mPageScrollPosition + 1, true);
1.2 bug1处理方案: 明确左右滑动条件,对异常情况进行处理。
if (mPageScrollPosition < mViewPager.getCurrentItem()) {
// 往右滑
if (xVelocity > VEL_THRESHOLD || (mPageScrollPositionOffset < 0.7f && xVelocity > -VEL_THRESHOLD)) {
mViewPager.setBannerCurrentItemInternal(mPageScrollPosition, true);
} else {
mViewPager.setBannerCurrentItemInternal(mPageScrollPosition + 1, true);
}
} else if (mPageScrollPosition == mViewPager.getCurrentItem()) {
// 往左滑
if (xVelocity < -VEL_THRESHOLD || (mPageScrollPositionOffset > 0.3f && xVelocity < VEL_THRESHOLD)) {
mViewPager.setBannerCurrentItemInternal(mPageScrollPosition + 1, true);
} else {
mViewPager.setBannerCurrentItemInternal(mPageScrollPosition, true);
}
} else{
//其他
mViewPager.setBannerCurrentItemInternal(mPageScrollPosition, true);
}
2.1 bug2处理方案:
这个bug是在复现第一个bug1是偶现的,主要就是当多次快速滑动时,BGABanner控件dispatchTouchEvent有时返回false,因此只接受了ActionDown事件,即停止了无限循环。而后续的up和cancel事件没有接受,即没有从新开启无限循环。
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (mAutoPlayAble) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
//停止循环
stopAutoPlay();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
//开启循环
startAutoPlay();
break;
}
}
//处理偶然的不分发事件的情况handled ==false
boolean handled = super.dispatchTouchEvent(ev);
if (!handled&&mAutoPlayAble) {
startAutoPlay();
}
return handled;
}
最后
以上就是追寻月饼为你收集整理的BGABanner-Android控件开启无限轮播后 ,快速滑动,ANR现象分析的全部内容,希望文章能够帮你解决BGABanner-Android控件开启无限轮播后 ,快速滑动,ANR现象分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复