RecyclerView的bug
使用 RecyclerView 加SwipeRefreshLayout下拉刷新的时候,adapter绑定的 List 在更新数据之前进行了 clear,而这时用户紧接着迅速上滑 RecyclerView,就会造成崩溃,而且异常不会报到我们的代码上,属于RecyclerView内部错误。
解决办法:
1. 在recyclerView进行刷新在时候,拦截触摸事件,使列表在刷新过程中不能滑动:
mRecyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mRefreshLayout.isRefreshing()) {
return true;
}
return false;
}
});
这个方法虽然管用,但也不能解决所有问题,因为不可避免的,有需要刷新过程中滑动列表的需求,或者其他诡异的操作(我就遇到了..),使刷新的过程中列表仍然滑动了,就还会崩溃。下面在这个方法的基础上,再增加一些措施。
- 首先,说明下我遇到的错误:
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{6129a2b position=50 id=-1, oldPos=0, pLpos:0 scrap [attachedScrap] tmpDetached no parent}
at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5297)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5479)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5440)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5436)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2224)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1551)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1511)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:595)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:3534)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3310)
at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1648)
at android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:343)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:860)
at android.view.Choreographer.doCallbacks(Choreographer.java:672)
at android.view.Choreographer.doFrame(Choreographer.java:605)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:846)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5432)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:735)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
从错误中可以看出,在LinearLayoutManager.onLayoutChildren方法中报错,我们打开这个方法发现它没有处理异常,所以我们可以自定义一个LinearLayoutManager类,并且捕获该异常.
public class MyLinearLayoutManager extends LinearLayoutManager {
public MyLinearLayoutManager(Context context) {
super(context);
}
public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public MyLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public boolean supportsPredictiveItemAnimations() {
return false;
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
} catch (Exception e) {
e.printStackTrace();
}
}
}
并将自定义的LinearLayoutManager添加到recyclerView中:
mRecyclerView.setLayoutManager(new MyLinearLayoutManager(getContext()));
至此基本可以解决这个问题了。而我这的代码还出现了另一个问题:
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 72(offset:72).state:84
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5504)
at android.support.v7.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:282)
at android.support.v7.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:336)
at android.support.v7.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:349)
at android.support.v7.widget.GapWorker.prefetch(GapWorker.java:356)
at android.support.v7.widget.GapWorker.run(GapWorker.java:387)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5432)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:735)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
同样是IndexOutOfBounsException,但并没被上面自定义的LinearLayoutManager捕获。通过走读我的代码,我发现了问题所在:
在重新增加列表项之前,就已经清空了列表,这时候如果来个诡异的滑动事件,就会导致上面这个问题的出现,所以将代码这样修改:
OK,这个问题就解决了~
但这个问题,根本原因还是在于RecyclerView内部的错误google并没有处理完善,最好的解决办法还是google来做,但在它出更新之前,我们只能自己处理了~~~
上一篇: Linux之组管理和权限管理
下一篇: Linux学习_组管理和权限管理