问题
RecycleView下拉刷新时,滑倒列表出现了崩溃。
崩溃信息如下:
UncaughtException detected: java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid item position 5(offset:5).state:15 androidx.recyclerview.widget.RecyclerView{8623f12 VFE...... .F...... 0,0-1080,1713 #7f0a0c9b app:id/recyclerView}, adapter:com.app.pinealgland.exposure.MultiTypeExposureAdapter@af886e3, layout:com.app.pinealgland.ui.base.widgets.pull.layoutmanager.CustomLineaLayoutManagerEx@b7cc8e0, context:com.app.pinealgland.activity.MainActivity@6a72786at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6183)at androidx.recyclerview.widget.GapWorker.prefetchPositionWithDeadline(GapWorker.java:288)at androidx.recyclerview.widget.GapWorker.flushTaskWithDeadline(GapWorker.java:345)at androidx.recyclerview.widget.GapWorker.flushTasksWithDeadline(GapWorker.java:361)at androidx.recyclerview.widget.GapWorker.prefetch(GapWorker.java:368)at androidx.recyclerview.widget.GapWorker.run(GapWorker.java:399)at android.os.Handler.handleCallback(Handler.java:793)at android.os.Handler.dispatchMessage(Handler.java:98)at android.os.Looper.loop(Looper.java:173)at android.app.ActivityThread.main(ActivityThread.java:6698)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782)
原因
下拉刷新时,我们一般会先clear()
掉旧数据,重新请求后addAll()
新数据,然后notifyDataSetChanged()
刷新列表显示。
伪代码如下:
//下拉刷新
onRefresh(){list.clear(); //清除旧数据loadData(){//网络请求新数据,耗时任务//请求成功onSucceed{list.addAll(newData); //添加新数据adapter.notifyDataSetChanged(); //刷新列表}}
}
由于网络请求是耗时的,在这期间用户可能会滑动列表。
由于已经clear()
列表中没有数据了,但是并没有立刻调用notifyDataSetChanged
去通知列表,此时滑动列表依旧会使用旧数据渲染,就会出现混乱,进而报越界异常IndexOutOfBoundsException
解决方案
- clear后立马notifyDataSetChanged,列表立马会变成空白,用户无法滑动。
list.clear(); //清除旧数据adapter.notifyDataSetChanged(); //立即刷新列表
- 等请求结束后再clear,addAll添加新数据后,掉notifyDataSetChanged一起刷新列表,这样即使用户滑动列表也不会出现数据混乱。
//请求成功onSucceed{list.clear(); //清除旧数据list.addAll(newData); //添加新数据adapter.notifyDataSetChanged(); //一起刷新列表}