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

问题描述 投票:1回答:4

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

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

带有1件或2件物品的Recyclerview很好,

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

例如:

如果我更改项目[5]处的复选框(项目ID为21,复选框启用),它还会触发OnCheckedChangeListener以用于其他项目,例如项目[1](项目ID为15,复选框启用)和项目[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
4个回答
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
投票

我想你需要通过holder.getAdapterPosition()获得这个位置。那应该是正确的。

为什么? Because

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

另外:在onClickListener中设置onBindViewHolder不是最佳实践,因为每次调用onBindViewHolder时都会设置监听器。将它设置在onCreateViewHolder中,因为onCreate仅在必须创建新的ViewHolder时调用,因此频率较低。


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

0
投票

您必须设置else语句,因为视图是Recycled并使用“旧”视图。

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

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

    }
}
© www.soinside.com 2019 - 2024. All rights reserved.