Мне нужно выбрать некоторые элементы, установив флажок в каждой записи 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);
}
});




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