Реализация флажка в Recylerview. MVVM Room ViewModel LiveData Recylerview Флажок - PullRequest
1 голос
/ 25 апреля 2019

Я реализовал Java-приложение с шаблоном MVVM для Android с помощью Room, ViewModel, LiveData, Recylerview.

  1. В рециркуляторе есть список предметов, и в каждом предмете есть флажок.
  2. Когда флажок в пункте повторного просмотра включен или отключен, модель обновляется в базе данных комнат через ViewModel.
  3. Чтобы прослушать флажок включения или отключения события на каждом просмотре реселлера пункт, я реализовал OnCheckedChangeListener.

Это нормально с рециркуляцией с 1 или 2 предметами,

Но когда увеличивается количество предметов в рециркуляторе, например> 10, когда я включаю или выключаю флажок, другие элементы в ракурсе также влияют.

Например:

Если я поменяю флажок у элемента [5] (идентификатор элемента равен 21, флажок включен), он также запускает OnCheckedChangeListener для других элементов, таких как item [1] (идентификатор элемента равен 15, флажок включен) и item [8] (идентификатор элемента равен 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);, это решило проблему, но это не рекомендуется, мне нужно найти другой механизм, чтобы избежать этого.

Ответы [ 4 ]

2 голосов
/ 25 апреля 2019
  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 голос
/ 25 апреля 2019

Я думаю, вам нужно получить позицию через holder.getAdapterPosition().Тогда это должно быть правильным.

Почему? Поскольку :

Обратите внимание, что в отличие от ListView, RecyclerView не будет вызывать этот метод снова, если позиция элемента изменяетсяв наборе данных, если только сам элемент не признан недействительным или новая позиция не может быть определена.... Если вам понадобится позиция элемента позже (например, в прослушивателе щелчков), используйте getAdapterPosition (), который будет иметь обновленную позицию адаптера.

Также: установка onClickListener внутриonBindViewHolder не лучшая практика, так как каждый раз, когда onBindViewHolder вызывается, слушатель устанавливается.Установите его в onCreateViewHolder, поскольку onCreate вызывается только тогда, когда необходимо создать новый ViewHolder и, следовательно, гораздо реже.

0 голосов
/ 25 апреля 2019

Вы должны установить оператор 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);
        });

    }
}
0 голосов
/ 25 апреля 2019

Хитрость заключается в том, чтобы установить флажок не активным и выполнять ручную проверку самостоятельно. Чтобы это работало, вы должны сохранить его статус в вашем списке данных и обновить его в соответствии со значением от 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);
        }
 });
...