RecyclerView在添加数据的时候发生了异常.
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{f82aa71 position=11 id=-1, oldPos=6, pLpos:6 scrap [attachedScrap] tmpDetached not recyclable(1) 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)
...
在RecyclerView#validateViewHolderForOffsetPosition(ViewHolder holder)中
if (holder.mPosition < 0 || holder.mPosition >= mAdapter.getItemCount()) {
throw new IndexOutOfBoundsException("Inconsistency detected. Invalid view holder "
+ "adapter position" + holder);
}
holder.mPosition >= mAdapter.getItemCount()为真,抛出了异常
发现mAdapter.getItemCount() 的值是正常的,但是holder.mPosition值有问题,在某种情况下和getItemCount的值一样大,此时条件为真。
接下来看了下RecyclerView中有5个方法改变了mPosition的值,分别是
Adapter#bindViewHolder()ViewHolder#resetInternal()ViewHolder#offsetPosition()ViewHolder#flagRemovedAndOffsetPosition()Recycler#tryGetViewHolderForPositionByDeadline()
分别打了断点,发现会引起崩溃的代码,会改变mPosition的有其中三个地方resetInternal(),offsetPosition(),bindViewHolder()。
resetInternal() 首先排除 ,因为mPosition = NO_POSITION;
然后仔细查看offsetPosition() 和bindViewholder()中的值发现,offsetPosition()的值mPosition += offset;会超出mPosition的值的范围。
所以现在就要去找这个方法被调用的时机和offset这个值的含义
- 查看
offsetPosition()的调用,发现调用分别来自RecyclerView与RecyclerView.Recycler两个的对应的insert,move和remove方法,以及ViewHolder的flagRemovedAndOffsetPosition(int, int, boolean)的方法 主要看就下面这个
void offsetPositionRecordsForInsert(int positionStart, int itemCount) {
//...
//这里将itemCount 传递给了offsetPosition
holder.offsetPosition(itemCount, false);
//...
mRecycler.offsetPositionRecordsForInsert(positionStart, itemCount);
requestLayout();
}
看起来在某个刷新数据的地方理解错了itemCount,找到我自己Adapter代码里面的
notifyItemRangeInserted(positionStart,itemCount);暂时修改为notifyDataSetChanged()不会报错了