奇怪的RecyclerView Checkbox onCheckChanged行为

时间:2016-07-23 15:05:28

标签: android checkbox android-recyclerview

我在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监听器?

2 个答案:

答案 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

处的复选框状态