解决java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder
bug日志:
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{ecef223 position=46 id=-1, oldPos=-1, pLpos:-1 no parent} android.support.v7.widget.RecyclerView{9876d9c VFED… … 0,0-1052,1651 #7f100210 app:id/recyclerView}, adapter:net.liexiang.dianjing.adapter.AdapterFeatureListRv@4b763a5, layout:android.support.v7.widget.LinearLayoutManager@90fe37a, context:net.liexiang.dianjing.ui.order.feature.FeatureListActivity@95fa84
at android.support.v7.widget.RecyclerView
R
e
c
y
c
l
e
r
.
v
a
l
i
d
a
t
e
V
i
e
w
H
o
l
d
e
r
F
o
r
O
f
f
s
e
t
P
o
s
i
t
i
o
n
(
R
e
c
y
c
l
e
r
V
i
e
w
.
j
a
v
a
:
5610
)
a
t
a
n
d
r
o
i
d
.
s
u
p
p
o
r
t
.
v
7.
w
i
d
g
e
t
.
R
e
c
y
c
l
e
r
V
i
e
w
Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5610) at android.support.v7.widget.RecyclerView
Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5610)atandroid.support.v7.widget.RecyclerViewRecycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5792)
at android.support.v7.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:285)
at android.support.v7.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:342)
at android.support.v7.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:358)
at android.support.v7.widget.GapWorker.prefetch(GapWorker.java:365)
at android.support.v7.widget.GapWorker.run(GapWorker.java:396)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:201)
at android.app.ActivityThread.main(ActivityThread.java:6806)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
原因:
通过查阅官方论坛和网上资料,基本锁定为RecyclerView官方的BUG
解决方式:
方式一:
继承封装LinearLayoutManager类,重写onLayoutChildren()方法,try-catch捕获该异常。
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
/**
-
Created by fx on 2019/9/11.
*/
public class XLinearLayoutManager extends LinearLayoutManager {public XLinearLayoutManager(Context context) {
super(context);
}public XLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}public XLinearLayoutManager(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) {
Log.e(“bug”, “crash in RecyclerView”);
}
}
}
LinearLayoutManager mLayoutManager=new XLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(mLayoutManager);
方式二:
数据变动(移除和增加),执行同步操作时,要保证RecyclerView的Adapter中的数据与需要同步的外部集合数据数量一致!
即每一次外部数据变动(移除和增加)时,都需主动Adapter做一次数据同步操作。以避免数据同步时内外数据不一致
数据同步方法:
notifyItemRangeRemoved();
notifyItemRangeInserted();
notifyItemRangeChanged();
notifyDataSetChanged();
异常代码:
public void setData(List list) {
if (list != null ) {
array.clear();
array.addAll(list);
notifyItemRangeChanged(0, list.size());
}
}
这里对该外部数据做了两个操作:先移除数据,然后添加数据,之后notify数据集。
array.addAll(list)时,Adapter的内部数据还处在array.clear()之前的状态,造成了Adapter内外数据不一致。
修复代码:
public void setData(List list) {
if (list != null ) {
int size = array.size();
array.clear();
notifyItemRangeRemoved(0, size);
array.addAll(list);
notifyItemRangeChanged(0, list.size());
}
}
我是用的是第一种方法,只要考虑到第二种方法在数据频繁变动时需要频繁进行同步操作。