0

I'm having problems with the following case, I have my list of questions with their respective check boxes, what I can't understand is why when I click check on "Yes" other boxes are checked, does anyone know why this anomaly happens.

This is the "yes" frame problem in question 1 and it is marked in question 8, 14 and so on randomly.

enter image description here

enter image description here

This is my structure.xml that contains the checkboxes

<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:animateLayoutChanges="true"
app:cardCornerRadius="2dp"
app:cardElevation="4dp"
app:cardUseCompatPadding="true">
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:animateLayoutChanges="true"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/icosemaforo"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"

            android:src="@drawable/ic_android" />

    </RelativeLayout>

    <LinearLayout
        android:id="@+id/contenedor_categoria1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
       android:layout_gravity="right"
        android:orientation="vertical"
        >
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            >
            <TextView
                android:id="@+id/txtnumeropregunta"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="5dp"
                android:layout_alignParentTop="true"
                android:text="N°"
                android:textSize="14sp"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/txtpreguntas"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="10dp"
                android:layout_marginTop="5dp"
                android:layout_marginEnd="20dp"
                android:layout_toStartOf="@+id/contenedorcheck"
                android:textSize="14sp"
                android:layout_toEndOf="@+id/txtnumeropregunta"
                android:textStyle="bold"
                android:text="Preguntas" />

            <LinearLayout
                android:id="@+id/contenedorcheck"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:layout_alignParentRight="true"
                android:layout_alignParentEnd="true"
                android:paddingEnd="20dp"
                >
                <CheckBox
                    android:id="@+id/chbksi"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentTop="true"

                    android:text="@string/check_si" />
                <CheckBox
                    android:id="@+id/chbkIVSS"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentTop="true"
                    android:visibility="gone"
                    android:text="@string/check_IVSS" />
                <CheckBox
                    android:id="@+id/chbkFSERV"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentTop="true"
                    android:visibility="gone"
                    android:text="@string/check_freserv" />
                <CheckBox
                    android:id="@+id/chbkno"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"

                    android:layout_marginEnd="10dp"
                    android:text="@string/check_no" />
                <CheckBox
                    android:id="@+id/chbkfmano"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:visibility="gone"
                    android:layout_marginEnd="10dp"
                    android:text="@string/check_fredmano" />
                <CheckBox
                    android:id="@+id/chbkDSS"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:visibility="gone"
                    android:layout_marginEnd="10dp"
                    android:text="@string/check_DSS" />

                <CheckBox
                    android:id="@+id/chbkna"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:visibility="gone"
                    android:layout_marginEnd="10dp"
                    android:text="@string/check_na" />
            </LinearLayout>

        </RelativeLayout>

    </LinearLayout>
</LinearLayout>

</androidx.cardview.widget.CardView>

And this is my adapter.tk where I hide and show some custom boxes

class preusoadapter(private val listpreguntaspreuso: ArrayList<epreguntas>) : RecyclerView.Adapter<PreUsoViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PreUsoViewHolder {
    val layoutInflater = LayoutInflater.from(parent.context)
    return PreUsoViewHolder(layoutInflater.inflate(R.layout.activity_estructura_listapreuso, parent, false))
}

override fun onBindViewHolder(holder: PreUsoViewHolder, position: Int) {
   val item = listpreguntaspreuso[position]
    holder.render(item)

holder.itemView.chbksi.isChecked = item.checkvalor != false

    if (position == 2)
    {
        holder.itemView.chbkno.visibility = View.GONE
        holder.itemView.chbksi.visibility = View.GONE
        holder.itemView.chbkIVSS.visibility = View.VISIBLE
        holder.itemView.chbkDSS.visibility = View.VISIBLE
    }else if (position == 6){
        holder.itemView.chbkFSERV.visibility = View.VISIBLE
        holder.itemView.chbkfmano.visibility = View.VISIBLE
        holder.itemView.chbkno.visibility = View.GONE
        holder.itemView.chbksi.visibility = View.GONE

    }else if (position == 14){
        holder.itemView.chbkna.visibility = View.VISIBLE
    }else if (position == 18){
        holder.itemView.chbkna.visibility = View.VISIBLE
    }else  if (position == 22){
        holder.itemView.chbkna.visibility = View.VISIBLE
    }else   if (position == 25){
        holder.itemView.chbkna.visibility = View.VISIBLE
    }
    else{

        holder.itemView.chbkno.visibility = View.VISIBLE
        holder.itemView.chbksi.visibility = View.VISIBLE
        holder.itemView.chbkna.visibility = View.GONE
        holder.itemView.chbkIVSS.visibility = View.GONE
        holder.itemView.chbkDSS.visibility = View.GONE
        holder.itemView.chbkFSERV.visibility = View.GONE
        holder.itemView.chbkfmano.visibility = View.GONE
    }

}

override fun getItemCount(): Int = listpreguntaspreuso.size

this is my class equestions(epreguntas)

 class epreguntas(
    var id_pregunta: String,
    var num_pregunta: String,
    var pregunta : String,
    var icono_estado: String,
    var checkvalor: Boolean

) {


}

any ideas on how to handle these events and prevent it from randomly checking other boxes.

kenny
  • 173
  • 9
  • Create a boolean variable in your POJO class, that is epreguntas I guess. Check that checkbox only which has a FALSE boolean value in your epreguntas POJO class in your onBindViewHolder method. Once you check your checkbox, make that boolean value TRUE in your POJO class. Also add one condition to make your checkbox checked/unchecked initially by using this boolean variable in onBindViewHolder method. – Bhavnik Sep 05 '22 at 15:30
  • This is how my class is asking(epreguntas) where are the variables that I use, so I have to create 1 boolean type variable, then I should also create another variable for the "No" box and thus control it so that it is not marked randomly? . – kenny Sep 05 '22 at 15:38
  • Simply create a boolean in your POJO class. Initially, that variable will have a False value. Then add one condition in onBindViewHolder, that will check if this boolean variable value is false, then leave that check box empty(i.e unchecked) else check it as checked. You don't need to create another boolean for NO. – Bhavnik Sep 05 '22 at 15:43
  • Okay, I'm going to apply the idea you shared with me, I'll tell you how it goes, thanks. – kenny Sep 05 '22 at 15:44
  • Also add a checkbox check listener, when you check any of them, then change a False value to True for a particular position in your ArrayList of adapter. For ex, if you checked the 3rd checkbox then do it like this, listpreguntaspreuso[position].your-boolean variable = true. Then notify adapter. – Bhavnik Sep 05 '22 at 15:49
  • add the variable checkvariable of boolean type, and I see that only 1 box is marked according to the condition but when I scroll and observe that what I have marked has been unmarked, I know that I am missing something else, about the Listener, in which part would I place it and how it would be applied in the onBindViewHolder – kenny Sep 05 '22 at 16:51

1 Answers1

0

If you want some checked state for your list items, you need to do three things:

  • store the checked state for the items, e.g. in the data itself, or (better) some data structure in the adapter
  • add a listener on your checkboxes that stores the checked/unchecked state for the current item
  • read that checked state in onBindViewHolder (where you're setting up a ViewHolder to display the current item) and check/uncheck the box as appropriate

I looked at your original question (before the edit) and I see you've added a checked boolean (checkvalor) to your Epreguntas data object, to store whether that item is checked or not. Personally I wouldn't do that - I feel like the checked state is a property of the list and not the data itself. So I'd store the checked state in a separate Set of all the checked position Ints, or a SparseBooleanArray where each index holds the checked state for position. But you can store it in the data object if you like!

So now you have somewhere to store the checked state, you need to set it when the checkbox is clicked, and read it when displaying an item.

You can set it with a click listener - I prefer this to an OnCheckedChangedListener because it only fires when the user taps it, and not when you set its checked state:

// I prefer setting the click listener in the ViewHolder class, but just to make things simple
override fun onBindViewHolder(holder: PreUsoViewHolder, position: Int) {
    val item = listpreguntaspreuso[position]

    holder.yourCheckBox.setOnClickListener {
        // toggle the checked state
        item.checkvalor = !item.checkvalor
        // update the display
        notifyItemChanged(position)
    }

Now your state changes in your item when the checkbox is clicked, so this line should work now:

holder.itemView.chbksi.isChecked = item.checkvalor != false

which you can just write as holder.itemView.chbksi.isChecked = item.checkvalor btw


A problem with storing your checked state in the data like this, is you have to persist it. If your Activity gets destroyed (e.g. during a rotation) or your whole app is recreated after being in the background, do you have those checkvalor values stored somewhere? Or will the data be recreated, with all the checkvalor values set to false?

If you store them in something like a SparseBooleanArray instead

// create a checked state lookup
private val checked = SparseBooleanArray(listpreguntaspreuso.size)

// read the checked state for an item
val isChecked = checked[position]

// toggle the checked state
checked[position] != checked[position]

then you can easily store that state when the parent Activity or Fragment hits onStop or onSaveInstanceState, and restore it when the parent is recreated. I've outlined that here if you want to look into it

cactustictacs
  • 17,935
  • 2
  • 14
  • 25
  • I appreciate your great contribution, the truth is that Kotlin is a huge world, I will continue investigating and improving, I am interested in this part about SparseBooleanArray, it helped me, thank you very much. – kenny Sep 06 '22 at 13:03
  • In the same onBindHolder can I get the content of the checkboxes? – kenny Sep 06 '22 at 13:37
  • @kenny `onBindViewHolder` is just where you take your *data* and *display it* in the `ViewHolder` you're given. You should be storing your data in the adapter, *which includes things like checkbox state*. You can't store it in the `ViewHolder`, e.g. looking at whether a checkbox widget is checked, because those VHs get reused to display different items, and the widget state gets lost. That's why you need to add a listener on the checkbox, so it can update *the checked state data in the adapter*, which is your source of truth. If you have other checkboxes, they need to do something similar – cactustictacs Sep 06 '22 at 17:53
  • I managed to get the data from the check, thanks for the help, but now another problem arose, you can't check 2 checks at the same time, if you check 1 it unchecks the other, I'm going crazy :D – kenny Sep 06 '22 at 22:18
  • @kenny you should post another question with your current code (don't edit this one!) so people can see how you're doing things. If you're storing the checked data, then you must be *clearing* one checked state when you're *setting* another – cactustictacs Sep 06 '22 at 23:46
  • ok @cactustictacs I just published it in another question, let's see if you take a look and share your idea on how I should implement what is required, I really appreciate your time, thanks. https://stackoverflow.com/questions/73636784/just-mark-1-checkbox-of-each-question-and-save-answer-of-each-position-kotlin – kenny Sep 07 '22 at 14:03