Android: How to check if a Checkbox is checked in an item of a RecyclerView

Issue

I’ve been trying to find out how I could check if a checkbox was checked in a list item in a RecyclerView. I have seen some articles online but I could not understand what they meant. If anyone could help, that’d be great.

Info about my app
This is a little snippet of what it does. It is a contacts app. On one screen it lists out ALL of the user’s contacts. I didn’t use the contacts picker for this. I displayed the list as a recyclerview, each item in the recyclerview has a checkbox. The user can check the checkbox for the contacts that they want to star. When they hit the save button the contacts that they checked will be on their favourites page which is the MainActivity.

I now need to find out how to see if an item is checked in a recycler view.

Here is the code for the adapter:

package krispo.callaid;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CheckedTextView;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

/**
 * Created by po on 9/8/2018.
 */

public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.MyViewHolder> {

private List<Contact> contactsList;


public class MyViewHolder extends RecyclerView.ViewHolder {
    public TextView name, number;
    public CheckBox checkBox;
    public MyViewHolder(View view) {
        super(view);
        name = (TextView) view.findViewById(R.id.name);
        number = (TextView) view.findViewById(R.id.number);
        checkBox = (CheckBox)view.findViewById(R.id.checkBox);


    }
}


public ContactAdapter(List<Contact> contactsList) {
    this.contactsList = contactsList;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.contact_row, parent, false);

    return new MyViewHolder(itemView);
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
    Contact contact = contactsList.get(position);
    holder.name.setText(contact.getName());
    holder.number.setText(contact.getPhoneNumber());

}

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

}

And this is the code for the contacts object:

package krispo.callaid;

import android.preference.CheckBoxPreference;

public class Contact {

private String name, phoneNumber,ID;
private boolean added;
private int position;


public Contact(){

}

    public Contact(String name, String phoneNumber,String ID, boolean added){
    this.name = name;
    this.phoneNumber = phoneNumber;
    this.ID = ID;
    this.added = added;
}

public String getName() {
    return this.name;
}

public void setName(String name) {
    this.name = name;
}

public String getPhoneNumber() {
    return this.phoneNumber;
}

public void setPhoneNumber(String phoneNumber) {
    this.phoneNumber = phoneNumber;
}

public String getID() {
    return this.ID;
}

public void setID(String ID) {
    this.ID = ID;
}

public boolean isAdded() {
    return this.added;
}

public void setAdded(boolean added) {
    this.added = added;
}

public int getPosition() {
    return position;
}

public void setPosition(int position) {
    this.position = position;
}
}

Here is the code for each item’s row:

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:attr/selectableItemBackground"
    android:clickable="true"
    android:focusable="true"
    android:orientation="vertical"
    android:paddingBottom="@dimen/row_padding_vertical"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/row_padding_vertical">

<TextView
    android:id="@+id/name"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_toEndOf="@+id/checkBox"
    android:layout_toRightOf="@+id/checkBox"
    android:text="Test"
    android:textColor="@android:color/black"
    android:textSize="25sp"
    android:textStyle="bold" />

<TextView
    android:id="@+id/number"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/name"
    android:layout_toEndOf="@+id/checkBox"
    android:layout_toRightOf="@+id/checkBox"
    android:text="Test"
    android:textColor="#7f8c8d"
    android:textSize="20sp" />

<CheckBox
    android:id="@+id/checkBox"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_toRightOf="@+id/number"
    android:layout_centerVertical="true" />

</RelativeLayout>

Thank you! I’m a bit new at this so sorry if it’s a bit messy.

Solution

The main problem is once you check an item and scroll the recycler view up or down such that the item goes out of the view, recycler view does not properly maintain the items which were checked while recreating the view. To maintain the state of the checked items, I have modified your adapter class as below:

package krispo.callaid;

import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CheckedTextView;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;

import com.cashrich.cashrich.adapter.WithdrawCardAdapter;

import java.text.DecimalFormat;
import java.util.List;

/**
 * Created by po on 9/8/2018.
 */

public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.MyViewHolder> {

    private List<Contact> contactsList;
    private Boolean[] chkArr;


    public class MyViewHolder extends RecyclerView.ViewHolder implements CheckboxListener {
        public TextView name, number;
        public CheckBox checkBox;
        public CustomSwitchListener myCustomSwitchListener;
        public MyViewHolder(View view,CustomSwitchListener myCustomSwitchListener) {
            super(view);
            name = (TextView) view.findViewById(R.id.name);
            number = (TextView) view.findViewById(R.id.number);
            checkBox = (CheckBox)view.findViewById(R.id.checkBox);
            this.myCustomSwitchListener=myCustomSwitchListener;
            checkBox.setOnCheckedChangeListener(myCustomSwitchListener);
        }

        @Override
        public  void updateCheck(int pos,boolean val)
        {
            if(val)
            {
                checkBox.setChecked(true);
            }
            else
            {
                checkBox.setChecked(false);
            }
        }
    }

    public Boolean[] getSelectedIds() {
        return chkArr;
    }

    public ContactAdapter(List<Contact> contactsList) {
        this.contactsList = contactsList;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.contact_row, parent, false);

        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        Contact contact = contactsList.get(position);
        holder.name.setText(contact.getName());
        holder.number.setText(contact.getPhoneNumber());

    }

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


    public interface CheckboxListener{
        void updateCheck(int pos,boolean val);
    }

    private class CustomSwitchListener implements CompoundButton.OnCheckedChangeListener {
        private int position;
        CheckboxListener checkboxListener;


        /**
         * Updates the position according to onBindViewHolder
         *
         * @param position - position of the focused item
         */
        public void updatePosition(int position,MyViewHolder holder) {
            this.position = position;
            checkboxListener=(CheckboxListener) holder;
        }

        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            chkArr[position]=isChecked;
            if(isChecked)
            {
                checkboxListener.updateCheck(position,true);
            }
            else
            {
                checkboxListener.updateCheck(position,false);
            }
        }
    }
}

This implements a class to maintain the state of the checked items and inform the same to the adapter while recreating the views. You can get the list of selected items with this variable private Boolean[] chkArr;

Answered By – Jeet Karmakar

Answer Checked By – Willingham (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *