IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter这个异常在之前就已经遇到过了,是发生在数据更新的时候。当时的解决办法是重写相应的LayoutManager的onLayoutChildren方法解决的,解决代码如下:
public class WrapContentLinearLayoutManager extends LinearLayoutManager {
public WrapContentLinearLayoutManager(Context context) {
super(context);
}
public WrapContentLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public WrapContentLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
}
}
}
今天又遇到了这个问题,发现是在adapter绑定的mData在清除最后一个数据之前的所有数据,然后再添加一组数据在最后一个数据之前,再调用notifyItemRangeInserted的时候出现的,话说的可能不是很清楚,用代码解释,如下:
public void set(List newData){
Object lastObject = mCollection.get(mCollection.size() - 1);
mData.clear();
mData.add(0, lastObject);
notifyItemInserted(position);
mData.addAll(0, newData);
notifyItemRangeInserted(position, newData.size());//不要问我为什么要先mData.add(0, lastObject),再mData.addAll(0, newData);而不是先mData.addAll(newData),再mData.add(lastObject),剧情需要
}
上述代码执行的时候就抛出了该异常,网上也有很多人出现该问题:
https://issuetracker.google.com/issues/37030377 #7
其实归根结底,还是adapter的item和数据源data不一致造成的!!!
解决办法如最上面说的重写相应LayoutManager的onLayoutChildren,在里面捕获异常即可,但是有人不提倡这么做:
https://issuetracker.google.com/issues/37030377 #12
大意是这样做会让RecyclerView处于不和逻辑的状态,有可能让RV崩溃,因为它失去了它的状态。
那还有什么解决办法呢?其实只要保持adapter的item和数据源data一致不就行了?!
正如之前在示例代码中所说的,
我们可以先调用mData.addAll(newData),再调用mData.add(lastObject),最后再调用notifyxxx即可。
这时你可能会用我的“剧情需要”来问我:万一某些情况就是需要先移出mData最后一项之前的数据,在添加新数据到mData最后一项之前呢?
于是我又屁颠屁颠的去google了,嘿嘿嘿,google果然是一个伟大的发明: