在Recylerview中实现复选框。 MVVM Room ViewModel LiveData Recylerview复选框

时间:2019-04-25 15:27:31

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

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

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

带有1或2个项目的recyclerview很好,

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

例如:

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

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);,它解决了该问题,但是不建议这样做,我需要找到另一种机制来避免这种情况。

4 个答案:

答案 0 :(得分:2)

  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());
    }
});

答案 1 :(得分:1)

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

为什么? Because

  

请注意,与ListView不同,RecyclerView不会调用此方法   如果项目的位置在数据集中发生了变化,则再次   项目本身无效或无法确定新位置。   ...如果以后需要某个项目的位置(例如单击   侦听器),请使用getAdapterPosition()来更新   适配器位置。

也:在onClickListener内设置onBindViewHolder并不是最佳实践,因为每次调用onBindViewHolder时都会设置监听器。在onCreateViewHolder中进行设置,因为onCreate仅在必须创建新的ViewHolder时才调用,因此不那么频繁。

答案 2 :(得分:0)

诀窍是将复选框设置为不可点击,并手动进行自我检查。为此,您必须将其状态保留在数据列表中,并根据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);
        }
 });

答案 3 :(得分:0)

您必须设置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);
        });

    }
}