我的场景
recyclerview的item 存在checkBox,checkBox的checkChangedListener中会修改数据源,同时调用notifyDataSetChanged函数。
// Adapter.class 伪代码
@Override
public void onBindViewHolder(viewHolder arg0, final int arg1) {
arg0.checkbox.setChecked(data.get(index).isCheck);
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// 修改数据源
changeData();
// 刷新界面
notifyDataSetChanged();
}
当持有该adapter的类也修改了数据源,同时调用了notifyDataSetChanged函数,Adapter就会触发onBindViewHolder(),checkBox的check被修改,又触发了onCheckedChanged的监听,这时就会crash。
// 持有Adapter的外部类 伪代码
void apiCall(){
// 更新数据
data = updateData();
// 更新UI
adapter.notifyDataSetChanged();
}
// crash info
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
crash的本意是RecyclerView正在layout或滚动,无法调用notifyDataSetChanged。
解决思路
1、避免在RecyclerView正在computing的时候,调用notifyDataSetChanged函数。使用handler的消息队列机制,当前队列消息正在处理computing,所以,可以向队列post一个notifyDataSetChanged的任务。这样就能避免RecyclerView正在computing
new Handler().post(new Runnable() {
@Override
public void run() {
notifyDataSetChanged();
}
});
2、因为是外部滑动或主动调用了notifyDataSetChanged函数,所以会触发onBindViewHolder,这里会主动的修改checkBox的check。可以在checkBox.setCheck()函数前后添加变量,用来判断是否是正在bind。
@Override
public void onBindViewHolder(viewHolder arg0, final int arg1) {
onBind = true;
arg0.checkbox.setChecked(data.get(index).isCheck);
onBind = false;
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// 修改数据源
changeData();
// 刷新界面
if(!onBind){
notifyDataSetChanged();
}
}
推荐使用第一种解决思路。方案二可能存在其他特殊情况,导致各种变量判断,增加了开发难度。
网友评论