В Android проверка Checkbox в RecyclerView автоматически проверяет некоторые другие флажки

Мне нужно выбрать некоторые элементы, установив флажок в каждой записи Android Recycler View. После того, как я установил флажок в позиции 0, каждый флажок в 9-й позиции также проверялся автоматически при прокрутке.

Как это преодолеть?

//В моем классе адаптера

   holder.approveCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
            Logger.infoLog("Checked Position ==> "+position+" boolean ==> "+b);
        }
    });
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
429
4

Ответы 4

Вы столкнулись с этой проблемой, потому что RecyclerView использует шаблон ViewHolder, с помощью которого он повторно использует дочернее представление и снижает потребление памяти.

вы можете подписаться на этот ссылка на сайт

или

Вы можете выполнить эти простые шаги.

1) Возьмите логическое значение в своем источнике данных, т.е. в списке вашего класса данных/модели.
(Это логическое значение будет хранить текущее состояние флажка)

2) В onClick событии флажка переключите значение этого логического значения для отображаемой модели данных и вызовите notifyDataSetChanged.
(Здесь не используйте onCheckedChanged)

3) При рендеринге поставить условие, следует ли помечать флажок как отмеченный или снятый, на основе этого логического значения.

Если вы можете получить position внутри анонимных реализаций, это означает, что это final. Как и внутри слушателя флажка.

final position вызовет расхождения между данными и пользовательским интерфейсом, потому что он не будет определен снова. На этом этапе должна быть ссылка на метод onBindViewHolder, который имеет лучшее объяснение, чем мое.

Для доступа к позиции как к не финальной вы можете использовать:

holder.getAdapterPosition()

Вам не нужно беспокоиться о том, что держатель был окончательным, потому что держатель - это строка, и она не будет повторно создаваться снова. Если он перерабатывается адаптером, то с ним проблем нет.

Используйте массив для хранения состояния элементов

В адаптере используйте Map или SparseBooleanArray (который похож на карту, но представляет собой пару ключ-значение int и boolean), чтобы сохранить состояние всех элементов в нашем списке элементов, а затем использовать ключи и значения для сравнения при переключении проверенного состояния

В адаптере создайте SparseBooleanArray

// sparse boolean array for checking the state of the items

    private SparseBooleanArray itemStateArray= new SparseBooleanArray();

затем в обработчике щелчка элемента onClick() используйте состояние элементов в itemStateArray для проверки перед переключением, вот пример

        @Override
        public void onClick(View v) {
            int adapterPosition = getAdapterPosition();
            if (!itemStateArray.get(adapterPosition, false)) {
                mCheckedTextView.setChecked(true);
                itemStateArray.put(adapterPosition, true);
            }
            else  {
                mCheckedTextView.setChecked(false);
                itemStateArray.put(adapterPosition, false);
            }
        }

также используйте разреженный логический массив, чтобы установить проверенное состояние, когда представление привязано

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    holder.bind(position);
}

@Override
public int getItemCount() {
    if (items == null) {
        return 0;
    }
    return items.size();
}

 void loadItems(List<Model> tournaments) {
    this.items = tournaments;
    notifyDataSetChanged();
}


class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    CheckedTextView mCheckedTextView;

    ViewHolder(View itemView) {
        super(itemView);
        mCheckedTextView = (CheckedTextView) itemView.findViewById(R.id.checked_text_view);
        itemView.setOnClickListener(this);
    }

    void bind(int position) {
        // use the sparse boolean array to check
        if (!itemStateArray.get(position, false)) {
            mCheckedTextView.setChecked(false);}
        else {
            mCheckedTextView.setChecked(true);
        }
    }

окончательный адаптер будет похож на это

Basi 18.01.2019 13:38

У меня возникли проблемы с этим, когда я назначил прослушиватель checkedChange в OnBindViewHolder, так как это будет вызываться несколько раз при повторном использовании. у меня сработало определение обратного вызова и прослушивателя в методе создания viewHolder.

public class CheckBoxHolder : RecyclerView.ViewHolder
    {
        public TextView line, destination, twd;
        public ImageView icon;
        public LinearLayout lineParent;
        public CheckBox checkBox;
        public CheckBoxHolder(View view, Action<int, CompoundButton.CheckedChangeEventArgs> listener) : base(view)
        {
            checkBox = view.FindViewById<CheckBox>(Resource.Id.check_checkBox);

            twd = view.FindViewById<TextView>(Resource.Id.check_twd);
            destination = view.FindViewById<TextView>(Resource.Id.check_dest);
            line = view.FindViewById<TextView>(Resource.Id.check_line);
            lineParent = view.FindViewById<LinearLayout>(Resource.Id.check_line_parent);
            icon = view.FindViewById<ImageView>(Resource.Id.check_icon); 
            view.Click += (sender, e) => {
                checkBox.Checked = !checkBox.Checked;
            };
            checkBox.CheckedChange += (object sender, CompoundButton.CheckedChangeEventArgs e) => listener(base.Position, e);
        }
    }

это код C# от xamarin, но концепция должна быть применима к вашей проблеме.

Другие вопросы по теме