java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position的一种规避方式

来源:互联网 发布:卧龙ol装备强化数据 编辑:程序博客网 时间:2024/05/19 19:15

公司项目需要使用大量的RecyclerView控件,需要经受数据频繁切换的考验,导致出现了大量的
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position异常。贴一段完整的error的log看一下:

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 20(offset:20).state:4304-07 17:00:25.011 E/AndroidRuntime(20589):     at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4663)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:4621)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:1994)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.support.v7.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:528)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1353)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.support.v7.widget.LinearLayoutManager.scrollBy(LinearLayoutManager.java:1181)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.support.v7.widget.LinearLayoutManager.scrollHorizontallyBy(LinearLayoutManager.java:1019)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.support.v7.widget.GridLayoutManager.scrollHorizontallyBy(GridLayoutManager.java:361)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.support.v7.widget.RecyclerView.scrollByInternal(RecyclerView.java:1525)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.support.v7.widget.RecyclerView.onGenericMotionEvent(RecyclerView.java:2582)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.View.dispatchGenericMotionEventInternal(View.java:9410)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.View.dispatchGenericMotionEvent(View.java:9391)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:2067)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:2018)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.View.dispatchGenericMotionEvent(View.java:9384)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:2067)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:2018)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.View.dispatchGenericMotionEvent(View.java:9384)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:2067)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:2018)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.View.dispatchGenericMotionEvent(View.java:9384)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewGroup.dispatchTransformedGenericPointerEvent(ViewGroup.java:2067)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewGroup.dispatchGenericPointerEvent(ViewGroup.java:2018)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.View.dispatchGenericMotionEvent(View.java:9384)04-07 17:00:25.011 E/AndroidRuntime(20589):     at com.android.internal.policy.PhoneWindow$DecorView.superDispatchGenericMotionEvent(PhoneWindow.java:2424)04-07 17:00:25.011 E/AndroidRuntime(20589):     at com.android.internal.policy.PhoneWindow.superDispatchGenericMotionEvent(PhoneWindow.java:1748)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.app.Activity.dispatchGenericMotionEvent(Activity.java:2822)04-07 17:00:25.011 E/AndroidRuntime(20589):     at com.android.internal.policy.PhoneWindow$DecorView.dispatchGenericMotionEvent(PhoneWindow.java:2391)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.View.dispatchPointerEvent(View.java:9522)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4230)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4096)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3642)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3695)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3661)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3787)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3669)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3844)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3642)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3695)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3661)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3669)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3642)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5922)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5896)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5857)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6025)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.os.MessageQueue.nativePollOnce(Native Method)04-07 17:00:25.011 E/AndroidRuntime(20589):     at android.os.Message

这个问题比较麻烦,是RecyclerView控件的一个bug,在stackoverflow上有各种各样的复现及解决方案,
然而,对我来说并没有什么卵用,解决不了我的问题。一次偶然的机会,在看一篇博客的时候找到了灵感。
规避这个问题的关键,其实在上述log的at android.support.v7.widget.GridLayoutManager.scrollHorizontallyBy(GridLayoutManager.java:361)这一行。
解决方法,就是在该方法内直接捕获IndexOutOfBoundsException。下面给出使用场景及部分关键代码。

使用场景:RecyclerView作为一个可以横向滑动的网状列表,数据频繁的切换,需要经常进行Adapter.notifyDataSetChanged()操作。
解决方案:

import android.content.Context;import android.support.v7.widget.GridLayoutManager;import android.support.v7.widget.RecyclerView;import android.util.AttributeSet;import android.util.Log;import android.view.View;/** * * Created by jxl on 2017/4/8. */public class OnegoGridLayoutManager extends GridLayoutManager {    public OnegoGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {        super(context, attrs, defStyleAttr, defStyleRes);    }    public OnegoGridLayoutManager(Context context, int spanCount) {        super(context, spanCount);    }    public OnegoGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {        super(context, spanCount, orientation, reverseLayout);    }    @Override    public boolean supportsPredictiveItemAnimations() {        return false;    }    @Override    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {        try {            return super.scrollHorizontallyBy(dx, recycler, state);        } catch (IndexOutOfBoundsException e) {            Log.e("hello", "scrollHorizontallyBy, IndexOutOfBoundsException");            e.printStackTrace();            return 0;        }    }}

然后在使用RecyclerView控件的时候,使用上面这个自定义LayoutManager即可。

如果使用场景有别于此处,比如RecyclerView控件需要上下滑动而不是左右滑动的列表样式,那么可以自定义LayoutManager继承自LinearLayoutManager,重写该类的onLayoutChildren方法,在方法内捕获异常。

说到底,其实并没有解决这个问题,只是通过捕获异常的方式使程序不至于崩溃。这样做可能带来一些数据异常的问题,所以有需要的话,还是慎重起见。
最后,感谢
http://blog.csdn.net/lovexieyuan520/article/details/50537846
这篇文章带来的灵感。
以上。

0 0
原创粉丝点击