'Broken CheckBoxes in RecyclerView

I am currently learning Android studio Java coding, and I got trouble. I created Recyclerview using cardView and added checkbox to cardView. If I create new object and check its checkbox, it works fine, strikethrough paintflag works. But if I add another object, which is below first, i cant check first object, it isn't changing its paintflag. The only way it work, is to check last added object, and it might work, (sometimes if i uncheck item above, the strikethrough paintflag isn't removing) for all cardView objects above.

Here's my CustomAdapter code:


import android.content.Context;
import android.graphics.Paint;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.lang.reflect.Array;
import java.util.ArrayList;

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> {
    private Context context;
    private ArrayList book_id, book_title, book_author, book_pages;
    CheckBox checkBox;

    CustomAdapter(Context context,
                  ArrayList book_id,
                  ArrayList book_title,
                  ArrayList book_author,
                  ArrayList book_pages){

         this.context = context;
         this.book_id = book_id;
         this.book_title = book_title;
         this.book_author = book_author;
         this.book_pages = book_pages;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
       LayoutInflater inflater = LayoutInflater.from(context);
       View view = inflater.inflate(R.layout.my_row, parent, false);
       return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {

        holder.book_id_txt.setText(String.valueOf(book_id.get(position)));
        holder.book_title_txt.setText(String.valueOf(book_title.get(position)));
        holder.book_author_txt.setText(String.valueOf(book_author.get(position)));
        holder.book_pages_txt.setText(String.valueOf(book_pages.get(position)));
    }

    @Override
    public int getItemCount() {
        return book_id.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {

        TextView book_id_txt, book_title_txt, book_author_txt, book_pages_txt;
        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            book_id_txt = itemView.findViewById(R.id.book_id_txt);
            book_title_txt = itemView.findViewById(R.id.book_title_txt);
            book_author_txt = itemView.findViewById(R.id.book_author_txt);
            book_pages_txt = itemView.findViewById(R.id.book_pages_txt);
            checkBox = itemView.findViewById(R.id.checkBox);
            checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    if (checkBox.isChecked()){

                        book_author_txt.setPaintFlags(book_author_txt.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
                        book_id_txt.setPaintFlags(book_id_txt.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
                        book_pages_txt.setPaintFlags(book_pages_txt.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
                        book_title_txt.setPaintFlags(book_title_txt.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);

                    } else {
                        book_author_txt.setPaintFlags(book_author_txt.getPaintFlags() & (~ Paint.STRIKE_THRU_TEXT_FLAG));
                        book_id_txt.setPaintFlags(book_id_txt.getPaintFlags() & (~ Paint.STRIKE_THRU_TEXT_FLAG));
                        book_pages_txt.setPaintFlags(book_pages_txt.getPaintFlags() & (~ Paint.STRIKE_THRU_TEXT_FLAG));
                        book_title_txt.setPaintFlags(book_title_txt.getPaintFlags() & (~ Paint.STRIKE_THRU_TEXT_FLAG));
                    }
                }
            });
        }
    }
}

If you need anything else, ask me. I am a beginner, so might be dummy) Please help me



Solution 1:[1]

To keep RecyclerView from recycling first add this lines to your CustomAdapter:

@Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getItemViewType(int position) {
        return position;
    }

also on your onBindViewHolder try to set your checkbox default status like:

if(condition){
holder.checkBox.setChecked(true);
}
else {
holder.checkBox.setChecked(false);
}

or if its simply unchecked default:

holder.checkBox.setChecked(false);

Solution 2:[2]

One more thing. I know it's an old question, but I encountered the problem today, nevertheless.

NEVER EVER NEVER use checkBox.setOnCheckedChangeListener

inside RecyclerView.Adapter<?>.onBindViewHolder!!!

It triggers during recycling!!

Use it like this instead:

        final DeviceItem item = items.get( position );
        if( null != holder.tToggle ) {
            Utils.logData( item.getName() + " is selected: " + item.isSelected() );
            holder.tToggle.setChecked( item.isSelected() );
            holder.tToggle.setOnClickListener( v -> {
                CheckBox ch = (CheckBox)v;
                item.setSelected( ch.isChecked() );
            } );
        }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Levente Gulyás
Solution 2 KaHa6uc