我在RecyclerView
项内有复选框的地方工作。我知道它的一些问题。但是,只有10个项目并且没有滚动错误的监听器被调用。
我有这样的事情:
private class MyAdapter extends RecyclerView.Adapter<MyViewHodler> {
ArrayList<String> items;
ArrayList<String> checkedList = new ArrayList<>();
...
public void onBindViewHolder(final MyViewHolder holder, int position) {
String item = items.get(position);
String check = checkedList.get(item);
if(check != null)
holder.vChecked.setChecked(true);
else
holder.vChecked.setChecked(false);
....
holder.vChecked.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
if (isChecked) {
checkedList.add(item);
} else {
checkedList.remove(item);
}
}
}
}
现在,奇怪的是,这个checkedChange调用是在不同的视图上进行的。我有一个只有10个项目的列表,适合在recyclerview中,没有滚动。我从外部更改数据(项目和检查列表),设置新数据并调用myAdapter.notifyDatasetChanged()
此调用会从已检查状态中删除另外一项。
例如,我检查了10个项目。我取消选中1个项目,然后根据它进行一些其他计算并调用myAdapter.notifyDatasetChanged()
。它还从其他9个项目中取消了另外一个元素。
即使没有滚动,为什么会为错误的视图调用onCheckedChange监听器?
答案 0 :(得分:4)
我发现了问题。我认为每个视图都会调用onBindViewHolder
来更改数据。但是我错了。
notifyDatasetChanged()
回收屏幕上的所有视图持有者,并从循环视图持有者池中随机选择视图来绑定新数据。因此,当我调用notifyDatasetChanged
时,视图符号在不同位置使用,因此更改了一个项目。
因此,我在回收器视图的onViewRecycled
方法中将侦听器移除为null。像这样:
@Override
public void onViewRecycled(MyViewHolder holder) {
super.onViewRecycled(holder);
holder.vChecked.setOnCheckedChangeListener(null);
}
这确实解决了这个问题。我知道这一点,但我认为如果没有滚动,查看器会被重用于相同的位置。但onDatasetChanged
会回收所有当前使用的视图持有者,并从随机池中再次使用它。
答案 1 :(得分:1)
这一行:String item = items.get(item);
让我烦恼。不应该是String item = items.get(position);
编辑:如果更改数据集的一个位置,请调用notifyItemChanged。除非完全更改,否则不要通知整个数据集。可能是这个。
编辑2:那么问题不在于在错误的视图上调用onCheckedChanged。它会在所有视图中调用,因为您始终更改onBindViewHolder