RecyclerView
RecyclerView copied to clipboard
更新列表时报异常`java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling`
这个异常是在我写一个备份手机安装包的APP是遇到的,Item中带有CheckBox
控件,选中的Item会备份。但是点击的同时稍微碰一下列表就会报此异常。
appAdapter.setViewClickListener(new AppAdapter.OnViewClickListener() {
@Override
public void onCheckedChange(int position, boolean isChecked) {
AppItem appItem = appAdapter.getItem(position);
appItem.isCheck = isChecked;
appAdapter.updateItem(appItem);
}
});
updateItem()方法如下:
public void updateItem(M data) {
int index = this.dataList.indexOf(data);
if(index >= 0) {
this.dataList.set(index, data);
if(this.headerView == null) {
this.notifyItemChanged(index);
} else {
this.notifyItemChanged(index + 1);
}
}
}
异常意思为:RecyclerView计算布局或者滚动时调用了不合状态的方法notifyItemChanged(int)
。
在StackOverFlow上找到了类似的问题和解释:
onBindViewHolder()
is not a method that initializeViewHolder
. This method is step of refresh each recycler item. When you callnotifyDataSetChanged()
,onBindViewHolder()
will be called as the number of each item times.So If you
notifyDataSetChanged()
put intoonCheckChanged()
and initializecheckBox
inonBindViewHolder()
, you will getIllegalStateException
because of circular method call.click checkbox ->
onCheckedChanged()
->notifyDataSetChanged()
->onBindViewHolder()
-> set checkbox -> onChecked...
解决办法有两种:
1.采用StackOverFlow的方法,添加flag。
private boolean onBind;
public ViewHolder(View itemView) {
super(itemView);
mCheckBox = (CheckBox) itemView.findViewById(R.id.checkboxId);
mCheckBox.setOnCheckChangeListener(this);
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(!onBind) {
// your process when checkBox changed
// ...
notifyDataSetChanged();
}
}
...
@Override
public void onBindViewHolder(YourAdapter.ViewHolder viewHolder, int position) {
// process other views
// ...
onBind = true;
viewHolder.mCheckBox.setChecked(trueOrFalse);
onBind = false;
}
2.在RecyclerView停止计算布局并且不滚动是更新数据
appAdapter.setViewClickListener(new AppAdapter.OnViewClickListener() {
@Override
public void onCheckedChange(int position, boolean isChecked) {
if (appListRv.getScrollState() == RecyclerView.SCROLL_STATE_IDLE
&& !appListRv.isComputingLayout()) {
AppItem appItem = appAdapter.getItem(position);
appItem.isCheck = isChecked;
appAdapter.updateItem(appItem);
}
}
});