Cannot call this method while RecyclerView is computing a layout or scrolling

我的场景

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();
        }
}

推荐使用第一种解决思路。方案二可能存在其他特殊情况,导致各种变量判断,增加了开发难度。

你可能感兴趣的:(Cannot call this method while RecyclerView is computing a layout or scrolling)