【问题标题】:Strange RecyclerView Checkbox onCheckChanged Behavior奇怪的 RecyclerView 复选框 onCheckChanged 行为
【发布时间】:2016-11-27 08:18:27
【问题描述】:

我在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);
                    }
                }
    }

}

现在,奇怪的是,这个 checkChange 调用是在不同的视图上进行的。我有一个只有 10 个项目的列表,并且适合 recyclerview,没有滚动。我在外部更改数据(项目和检查列表),设置新数据并调用myAdapter.notifyDatasetChanged()

此调用从选中状态中删除了一项。

例如,我检查了 10 个项目。我取消选中 1 项,并基于此进行一些其他计算并调用 myAdapter.notifyDatasetChanged()。它还会取消选中其他 9 个项目中的一个元素。

所以即使不滚动,为什么 onCheckedChange 监听器会为错误的视图调用?

【问题讨论】:

    标签: android checkbox android-recyclerview


    【解决方案1】:

    这一行:String item = items.get(item);

    这让我很困扰。不应该是String item = items.get(position);

    编辑:如果您更改数据集的一个位置,请调用 notifyItemChanged。不要通知整个数据集,除非它已经完全改变。可能是这个。

    编辑 2:那么问题不在于在错误的视图上调用了 onCheckedChanged。在所有视图中都会调用它,因为您总是在 onBindViewHolder 处更改复选框状态

    【讨论】:

    • 基于一个项目,我更改了一些反映在所有其他项目中的计算。所以我需要调用 notifyDatasetChanged
    • 我明白了。这就是为什么总是调用onCheckedChanged 的原因。您总是在onBindViewHolder 处更改复选框的状态,并且当您通知数据集已更改时,会为 RecyclerView 中的每个项目调用一次此方法。
    • 但它应该只在绑定视图上调用。由于视图不会被回收或滚动。而不是其他一些随机项目..
    • 不管怎样,如果显示十项,则十项绑定到列表。如果您调用notifyDatasetChanged,则每个项目都会调用onBindViewHolder。他们会反弹。
    • 抱歉回复晚了。但是,我发现出了什么问题。我知道每个项目都会调用 onBindViewHolder,但只是为了用新数据重新填充布局。但是我错了。我添加了一个答案
    【解决方案2】:

    我发现了问题所在。我认为每个视图都会调用onBindViewHolder 来更改数据。但是我错了。

    notifyDatasetChanged() 回收屏幕上的所有视图持有者,并从回收的视图持有者池中随机挑选视图持有者来绑定新数据。所以当我调用notifyDatasetChanged时,viewholder被用在了不同的位置,因此又改变了一项。

    所以,我在回收器视图的onViewRecycled 方法中将侦听器删除为 null。像这样:

        @Override
        public void onViewRecycled(MyViewHolder holder) {
            super.onViewRecycled(holder);
    
            holder.vChecked.setOnCheckedChangeListener(null);
        }
    

    这确实解决了问题。我意识到了这一点,但我认为如果没有滚动,视图会被重复用于相同的位置。但是onDatasetChanged 会回收所有当前使用的视图持有者,并从随机池中再次使用它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-01
      • 2020-08-29
      • 1970-01-01
      • 1970-01-01
      • 2011-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多