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()
不會報錯了