Radio buttons inside RecyclerView keep randomly being unchecked even when I explicitly set the checked state on a radio button

Viewed 266

To make ViewHolder treat each radio button separately and not reuse previous radio button's state I stored the state of whether or not a radio button item is checked in a list of booleans and set the radio buttons state according to that list. but when I scroll down and up the toggled radio buttons get untoggled randomly even though the isCheckedList contains the right boolean information for each radio button(I print the list with logd() to verify if it actually stores the states)

Any Idea of what I'm missing?

class QuestionAdapter(context: Context) :
    RecyclerView.Adapter<QuestionAdapter.QuestionViewHolder>() {

    private val listOfQuestion: List<String>
    private val listSize = 20
    private val isCheckedList: MutableList<Boolean> = MutableList(listSize) { false }

   //Initialize a list of 20 questions. 
    init {
        val allQuestions = context.resources.getStringArray(R.array.questions).toList()

        listOfQuestion = allQuestions
            .shuffled()
            .take(listSize)
    }

    class QuestionViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
        val questionText = view.findViewById<TextView>(R.id.question)
        val radioButton = view.findViewById<RadioButton>(R.id.yes)
       
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuestionViewHolder {
        val layout = LayoutInflater
            .from(parent.context)
            .inflate(R.layout.item_view, parent, false)
        return QuestionViewHolder(layout)
    }

    override fun onBindViewHolder(holder: QuestionViewHolder, position: Int) {

        val item = listOfQuestion[position]
        holder.questionText.text = item

        holder.radioButton.isChecked = isCheckedList[position]
        holder.radioButton.setOnCheckedChangeListener { _, isChecked ->
                isCheckedList[holder.adapterPosition] = isChecked
                Log.d("Adapter", "list: $isCheckedList ")
        }
    }
    
    override fun getItemCount(): Int {
        return listOfQuestion.size
    }


}
2 Answers

I solved the problem by adding this line of code holder.radioGroup.clearCheck() before setting the state of radio buttons. For more details this is a blog talking about the same issue and how he solved it.

You need to clear the selection on the radio button before setting its correct value.

holder.radioGroup.clearCheck()

This way, the RadioGroup clears its selection, ready to receive an input that will trigger the correct RadioButton as checked.

But you need to be aware that this might call your onCheckedChanged listeners and could bring unexpected outcomes. But there is a work around for the resulting problem.

// Nullify listener
holder.radioGroup.setOnCheckedChangeListener(null);

// Clear selection
holder.radioGroup.clearCheck();

// Reset listener after selection has been cleared
holder.radioGroup.setOnCheckedChangeListener(checkedChangeListener);
Related