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;
            }
        });

这个方法虽然管用,但也不能解决所有问题,因为不可避免的,有需要刷新过程中滑动列表的需求,或者其他诡异的操作(我就遇到了..),使刷新的过程中列表仍然滑动了,就还会崩溃。下面在这个方法的基础上,再增加一些措施。

  1. 首先,说明下我遇到的错误:
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来做,但在它出更新之前,我们只能自己处理了~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值