Art*_*hur 128 android android-recyclerview
我正在尝试使用notifyDataSetChanged()更新recycleview的项目.
这是我在recycleview适配器中的onBindViewHolder()方法.
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
//checkbox view listener
viewHolder.getCheckbox().setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//update list items
notifyDataSetChanged();
}
});
}
Run Code Online (Sandbox Code Playgroud)
我选中一个复选框后,我想要做的是更新列表项.我得到了一个非法的例外:"Cannot call this method while RecyclerView is computing a layout or scrolling"
java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
at android.support.v7.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:1462)
at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onChanged(RecyclerView.java:2982)
at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyChanged(RecyclerView.java:7493)
at android.support.v7.widget.RecyclerView$Adapter.notifyDataSetChanged(RecyclerView.java:4338)
at com.app.myapp.screens.RecycleAdapter.onRowSelect(RecycleAdapter.java:111)
Run Code Online (Sandbox Code Playgroud)
我也使用了notifyItemChanged(),同样的例外.任何秘密的更新方式,以通知适配器的东西发生了变化?
小智 138
您应该将方法'setOnCheckedChangeListener()'移动到ViewHolder,它是适配器上的内部类.
onBindViewHolder()不是初始化的方法ViewHolder.此方法是刷新每个回收物品的步骤.当你打电话时notifyDataSetChanged(),onBindViewHolder()会被称为每个项目的次数.
因此,如果您notifyDataSetChanged()输入onCheckChanged()并初始化checkBox onBindViewHolder(),则由于循环方法调用,您将获得IllegalStateException.
单击复选框 - > onCheckedChanged() - > notifyDataSetChanged() - > onBindViewHolder() - >设置复选框 - > onChecked ...
简单地说,你可以通过在Adapter中放一个标志来解决这个问题.
试试这个,
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;
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*iDS 42
您可以在进行更改之前重置上一个侦听器,但不会出现此异常.
private CompoundButton.OnCheckedChangeListener checkedListener = new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//Do your stuff
});;
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
holder.checkbox.setOnCheckedChangeListener(null);
holder.checkbox.setChecked(condition);
holder.checkbox.setOnCheckedChangeListener(checkedListener);
}
Run Code Online (Sandbox Code Playgroud)
cyb*_*gen 39
Using a Handler for adding items and calling notify...() from this Handler fixed the issue for me.
小智 24
我不太清楚,但我也有同样的问题.我通过使用来解决这个onClickListner问题checkbox
viewHolder.mCheckBox.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (model.isCheckboxBoolean()) {
model.setCheckboxBoolean(false);
viewHolder.mCheckBox.setChecked(false);
} else {
model.setCheckboxBoolean(true);
viewHolder.mCheckBox.setChecked(true);
}
notifyDataSetChanged();
}
});
Run Code Online (Sandbox Code Playgroud)
试试这个,这可能会有所帮助!
bru*_*uce 12
protected void postAndNotifyAdapter(final Handler handler, final RecyclerView recyclerView, final RecyclerView.Adapter adapter) {
handler.post(new Runnable() {
@Override
public void run() {
if (!recyclerView.isComputingLayout()) {
adapter.notifyDataSetChanged();
} else {
postAndNotifyAdapter(handler, recyclerView, adapter);
}
}
});
}
Run Code Online (Sandbox Code Playgroud)
当您有消息错误时:
Cannot call this method while RecyclerView is computing a layout or scrolling
Run Code Online (Sandbox Code Playgroud)
简单,只需执行导致异常的原因:
RecyclerView.post(new Runnable() {
@Override
public void run() {
/**
** Put Your Code here, exemple:
**/
notifyItemChanged(position);
}
});
Run Code Online (Sandbox Code Playgroud)
找到一个简单的解决方
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private RecyclerView mRecyclerView;
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
mRecyclerView = recyclerView;
}
private CompoundButton.OnCheckedChangeListener checkedChangeListener
= (compoundButton, b) -> {
final int position = (int) compoundButton.getTag();
// This class is used to make changes to child view
final Event event = mDataset.get(position);
// Update state of checkbox or some other computation which you require
event.state = b;
// we create a runnable and then notify item changed at position, this fix crash
mRecyclerView.post(new Runnable() {
@Override public void run() {
notifyItemChanged(position));
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我们为recyclerview准备好处理它时创建一个可运行的notifyItemChanged.
起初我认为Moonsoo 的答案(已接受的答案)对我不起作用,因为我无法setOnCheckedChangeListener()在 ViewHolder 构造函数中初始化我的,因为我每次都需要绑定它,以便它获得更新的位置变量。但我花了很长时间才明白他在说什么。
这是他正在谈论的“循环方法调用”的一个例子:
public void onBindViewHolder(final ViewHolder holder, final int position) {
SwitchCompat mySwitch = (SwitchCompat) view.findViewById(R.id.switch);
mySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
data.delete(position);
notifyItemRemoved(position);
//This will call onBindViewHolder, but we can't do that when we are already in onBindViewHolder!
notifyItemRangeChanged(position, data.size());
}
}
});
//Set the switch to how it previously was.
mySwitch.setChecked(savedSwitchState); //If the saved state was "true", then this will trigger the infinite loop.
}
Run Code Online (Sandbox Code Playgroud)
与此唯一的问题是,当我们需要初始化开关打开或关闭(从过去的保存状态,例如),它在调用可能调用监听nofityItemRangeChanged其通话onBindViewHolder一次。你不能打电话onBindViewHolder的时候,你已经是onBindViewHolder],因为你不能notifyItemRangeChanged,如果你已经在通知该项目范围已经改变的中间。但我只需要更新 UI 以显示它的开启或关闭,并不想真正触发任何东西。
这是我从JoniDS 的回答中学到的解决方案,可以防止无限循环。只要我们在设置Checked之前将监听器设置为“null”,那么它就会在不触发监听器的情况下更新UI,避免死循环。然后我们可以设置监听器。
JoniDS的代码:
holder.checkbox.setOnCheckedChangeListener(null);
holder.checkbox.setChecked(condition);
holder.checkbox.setOnCheckedChangeListener(checkedListener);
Run Code Online (Sandbox Code Playgroud)
我的例子的完整解决方案:
public void onBindViewHolder(final ViewHolder holder, final int position) {
SwitchCompat mySwitch = (SwitchCompat) view.findViewById(R.id.switch);
//Set it to null to erase an existing listener from a recycled view.
mySwitch.setOnCheckedChangeListener(null);
//Set the switch to how it previously was without triggering the listener.
mySwitch.setChecked(savedSwitchState); //If the saved state was "true", then this will trigger the infinite loop.
//Set the listener now.
mySwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
data.delete(position);
notifyItemRemoved(position);
//This will call onBindViewHolder, but we can't do that when we are already in onBindViewHolder!
notifyItemRangeChanged(position, data.size());
}
}
});
}
Run Code Online (Sandbox Code Playgroud)
当您调用时,您的 CheckBox 项正在更改 drawable,notifyDataSetChanged();因此会发生此异常。尝试notifyDataSetChanged();在帖子中调用您的观点。例如:
buttonView.post(new Runnable() {
@Override
public void run() {
notifyDataSetChanged();
}
});
Run Code Online (Sandbox Code Playgroud)
为什么不检查RecyclerView.isComputingLayout()状态如下?
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
private RecyclerView mRecyclerView;
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
mRecyclerView = recyclerView;
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
viewHolder.getCheckbox().setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (mRecyclerView != null && !mRecyclerView.isComputingLayout()) {
notifyDataSetChanged();
}
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
77654 次 |
| 最近记录: |