Проблема в том, что хотя на первый взгляд код выглядит правильно, на самом деле происходит то, что когда вы вызываете holder.radioGroup.check()
, он запускает ваш onCheckedChanged()
обработчик событий точно так же, как если бы пользователь его инициировал.
Поскольку виды перерабатываются, вид в позиции 0 повторно используется для позиции 8 в списке.Таким образом, вызов check()
в onBindViewHolder()
вызовет onCheckedChanged()
, с проверенным переключателем из позиции 0, все еще проверенным (то есть checkedId
и radioGroup. getCheckedRadioButtonId()
вернут идентификатор радиокнопки, проверенной, когда представление использовалось впозиция 0).
Реальная суть заключается в следующем
models.get(clickedPos).setChecked(radioButtonID);
Рассмотрите первые абзацы ответа, и вы поймете, что это (неправильно) обновит элемент модели в позиции 8с radioButtonID
, который был проверен, когда это представление использовалось в позиции 0.
Один из способов решить эту проблему - провести различие между изменением, инициированным пользователем, и изменением, инициированным привязкой.Например, вы можете сделать это, добавив поле к ViewHolder
, чтобы указать, является ли представление в настоящее время обязательным.
class ViewHolder extends RecyclerView.ViewHolder{
TextView selectedAnswer;
RadioGroup radioGroup;
boolean isBinding;
ViewHolder(View itemView) {
super(itemView);
radioGroup = itemView.findViewById(R.id.radioGroup);
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
int position = getAdapterPosition();
RadioButton radioButton = (RadioButton) group.findViewById(checkedId);
/* Only update the model when onCheckedChange() was initiated by the user clicking
a radio button, not when the adapter is binding the view. In that scenario, we
are only interested in passing information FROM the model TO the view. */
if( !isBinding ) {
models.get(position).setChecked(checkedId);
models.get(position).setSelectedAns(radioButton != null ? radioButton.getText().toString() : "");
}
selectedAnswer.setText( models.get(position).getSelectedAns() );
}
});
...
}
}
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
holder.isBinding = true;
...
/* When calling check() here, we invoke onCheckedChanged(), which will
update the textview that displays the selected answer - so no need to call
holder.selectedAnswer.setText( models.get(position).getSelectedAns() )
from here */
holder.radioGroup.check(models.get(position).getChecked());
holder.isBinding = false;
}