【问题标题】:Implementing checkbox in a Recylerview. MVVM Room ViewModel LiveData Recylerview Checkbox在 Recyclerview 中实现复选框。 MVVM Room ViewModel LiveData Recyclerview 复选框
【发布时间】:2019-04-25 15:27:30
【问题描述】:

我已经用 Room、ViewModel、LiveData、Recylerview 实现了一个 MVVM 模式的 android java 应用程序。

  1. recyclerview 有一个项目列表,每个项目都有一个复选框。
  2. 当 recyclerview 项目的复选框被启用或禁用时, 模型通过 ViewModel 在房间数据库中更新。
  3. 在每个recyclerview上监听复选框启用或禁用事件 项目,我已经实现了一个 OnCheckedChangeListener。

recyclerview 可以有 1 或 2 个项目,

但是当 recyclerview 项目增加时,比如 >10 个项目,当我启用或禁用该复选框时,recyclerview 中的其他项目也会受到影响。

例如:

如果我更改 item[5] 处的复选框(项目 ID 为 21,复选框启用), 它还为其他项目触发 OnCheckedChangeListener,如 item[1](项目 ID 为 15,启用复选框)和 item[8](项目 ID 为 18,启用复选框)。

Logcat:

2019-04-25 11:15:33.343 9890-9890/com.hardian.mvvm.sample D/RVAdapter: setOnCheckedChange--- ID :21 isRetryEnabled; false isChecked true
2019-04-25 11:15:33.405 9890-9890/com.hardian.mvvm.sample D/RVAdapter: setOnCheckedChange--- ID :15 isRetryEnabled; false isChecked true
2019-04-25 11:15:33.415 9890-9890/com.hardian.mvvm.sample D/RVAdapter: setOnCheckedChange--- ID :18 isRetryEnabled; false isChecked true

代码:在我的 StatusRecyclerViewAdapter

 @Override
    public void onBindViewHolder(StatusViewHolder holder, int position) {
        StatusItem  statusItem = mDataSet.get(position);

        if (statusItem != null) {
            cbStatus.setChecked(statusItem.isRetryEnabled());

            cbStatus.setOnCheckedChangeListener((buttonView, isChecked) -> {
                Log.d("RVAdapter", "setOnCheckedChange--- ID :" + statusItem.getId()+ " isRetryEnabled; "+statusItem.isRetryEnabled()+" isChecked "+isChecked);
                //update the model via the activitiy's viewmodel through the onStatusCheckBoxChangeListener interface.
                if (onStatusCheckBoxChangeListener != null)
                    onStatusCheckBoxChangeListener.onStatusCheckBoxChanged(statusItem,isChecked);
            });

        }
    }

我需要一个解决方案来解决 Recylerview 回收问题。

注意: 我试过this.setIsRecyclable(false);,它解决了这个问题,但不推荐,我需要找到另一种机制来避免这种情况。

【问题讨论】:

    标签: android android-recyclerview android-room android-viewmodel


    【解决方案1】:
    1. 为您的复选框设置标签并从标签中获取项目。
    2. 不要使用 setOnCheckedChangeListener,而是使用 setOnClickListener。

    代码:

    cbStatus.setTag(statusItem);
    cbStatus.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            CheckBox cb = (CheckBox) v;
            StatusItem item = (StatusItem) cb.getTag();
            if (onStatusCheckBoxChangeListener != null)
                onStatusCheckBoxChangeListener.onStatusCheckBoxChanged(item,cb.isChecked());
        }
    });
    

    【讨论】:

    • 谢谢你,效果很好。标记有效,现在多个触发器的问题消失了。
    • 哇,感谢 setTag 部分。不知道可以通过它在视图上设置模型类。
    【解决方案2】:

    我认为您需要通过holder.getAdapterPosition() 获得该职位。那么它应该是正确的。

    为什么? Because

    注意,与ListView不同的是,RecyclerView不会调用这个方法 如果项目在数据集中的位置发生变化,除非 项目本身无效或无法确定新位置。 ...如果您稍后需要某个项目的位置(例如,单击 listener),使用 getAdapterPosition() 将更新 适配器位置。

    另外:在onBindViewHolder 内设置onClickListener 不是最佳做法,因为每次调用onBindViewHolder 时都会设置侦听器。将其设置在 onCreateViewHolder 中,因为 onCreate 仅在必须创建新 ViewHolder 时调用,因此频率要低得多。

    【讨论】:

    • Viewholder 也不会被回收吗?我的意思是每个项目都调用所有方法。
    • 并非每个项目都有其“自己的”ViewHolder。 ViewHolders 可能会在您滚动时获得不同的项目,因为仅设置一个新项目而不是膨胀一个完整的布局要便宜得多
    • 是的。另外,您在访问元素时不需要使用持有者实例。
    【解决方案3】:

    诀窍是设置复选框不可点击并自己手动检查。为此,您必须在数据列表中保留其状态并根据来自CheckBox 的值对其进行更新。

    第一组CheckBox不可点击。

        android:clickable="false"
        android:focusable="false"
        android:focusableInTouchMode="false"
    


    接下来设置你的ClickListener

      holder.cbStatus.setOnClickListener(v -> {
            StatusItem  statusItem = mDataSet.get(position);
    
            if (cbStatus.isChecked()) {
                cbStatus.setChecked(false);
                statusItem.setChecked(false);
    
            } else {
                cbStatus.setChecked(true);
                statusItem.setChecked(true);
            }
     });
    

    【讨论】:

    • 我了解点击监听器的工作原理,而不是选中的更改监听器。感谢您提供的信息。此处使用 viewmodel Livedata Room 模式,数据集更新仅通过 AndroidViewModel 对象。
    【解决方案4】:

    您必须设置 else 语句,因为该视图已被回收并使用“旧”视图。

    或者你可以做这样的事情:

        @Override
    public void onBindViewHolder(StatusViewHolder holder, int position) {
        StatusItem  statusItem = mDataSet.get(position);
    
        youCheckBox.setChecked(false);
    
        if (statusItem != null) {
            cbStatus.setChecked(statusItem.isRetryEnabled());
    
            cbStatus.setOnCheckedChangeListener((buttonView, isChecked) -> {
                Log.d("RVAdapter", "setOnCheckedChange--- ID :" + statusItem.getId()+ " isRetryEnabled; "+statusItem.isRetryEnabled()+" isChecked "+isChecked);
                //update the model via the activitiy's viewmodel through the onStatusCheckBoxChangeListener interface.
                if (onStatusCheckBoxChangeListener != null)
                    onStatusCheckBoxChangeListener.onStatusCheckBoxChanged(statusItem,isChecked);
            });
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-03-17
      • 2018-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多