项目中用到RecyclerView,然后每个item里面有checkbox,初始化的时候会设置checkbox的选中状态,然后当列表上下滑动的时候已选中的checkbox会变成未选中状态,再点击这个checkbox就会报错,如下
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling android.support.v7.widget.RecyclerView{629eaac VFED..... ......ID 0,0-1080,1719 #7f090071 app:id/contacts_personnel_rv}, adapter:com.pkpm.huaxi.contacts.adapter.PersonSelectAdapter@2618375, layout:android.support.v7.widget.LinearLayoutManager@b10cf0a, context:com.pkpm.huaxi.home.activity.SelectOnePersonActivity@ca5cf42
at android.support.v7.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:2880)
at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onItemRangeChanged(RecyclerView.java:5292)
at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyItemRangeChanged(RecyclerView.java:12012)
at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyItemRangeChanged(RecyclerView.java:12002)
at android.support.v7.widget.RecyclerView$Adapter.notifyItemChanged(RecyclerView.java:7086)
at com.pkpm.huaxi.contacts.adapter.PersonSelectAdapter$1.onCheckedChanged(PersonSelectAdapter.java:95)
at android.widget.CompoundButton.setChecked(CompoundButton.java:171)
at com.pkpm.huaxi.contacts.adapter.PersonSelectAdapter.onBindViewHolder(PersonSelectAdapter.java:84)
at android.support.v7.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6781)
at android.support.v7.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6823)
at android.support.v7.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5752)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6019)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5858)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5854)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2230)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1557)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:612)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924)
at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3641)
at android.support.v7.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1877)
at android.support.v7.widget.RecyclerView$1.run(RecyclerView.java:407)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:968)
at android.view.Choreographer.doCallbacks(Choreographer.java:780)
at android.view.Choreographer.doFrame(Choreographer.java:712)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:954)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6600)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:518)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:821)
从报错来看,是说当RecyclerView计算布局或滑动过程中不能调用notifyItemChanged这个方法,但是我并没有在滑动过程中调用notifyItemChanged,怎么回事呢,需要从上下滑动时checkbox的选中状态会消失这个问题入手,那为什么会出现这个问题呢?
原因在于Recyclerview滚动时自动调用 onCheckedChanged 导致的
- CheckBox在执行setChecked时会触发OnCheckedChange处理程序;
- Adapter采用的是控件重用机制,就是当列表往上下拖时,那些被拖出屏幕外的控件会重用,由于该item获取到的数据项(dataList.get(index))往往使用了final,所以在执行CheckBox.setChecked(true/false);
触发该控件的OnCheckedChange处理程序,而这个处理程序指向的数据项是前一次绑定的那行数据,这样就可能导致
dataList中的某个数据被意外修改,进而引起程序行为的不确定。
具体解决办法在onBindViewHolder中设置选中状态之间设置checkbox的状态变化监听事件为null
//在初始化CheckBox状态和设置状态变化监听事件之前,先把状态变化监听事件设置为null
holder.checkBox.setOnCheckedChangeListener(null);
if (bean.getIsSelected()) {
viewHolder.checkBox.setChecked(true);
} else {
viewHolder.checkBox.setChecked(false);
}
viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// 这里就是调用notifyItemChanged
} else {
}
}
});