Search code examples
javaandroid-studioandroid-recyclerviewandroid-databinding

Binding recycler view according to a condition


I have a tasks app where the person can click on the checkbox of the task and the colour of the task will change. But i'm having a problem with binding this condition with the view. When the checkbox is checked, the colour changes but when the app is closed and opened again, the checkbox is not checked and the color goes back to normal. How can i retain the checked state of the checkbox and the text colour in this case.

Picture 1
Picture 2
Picture 3

My Adapter class -

 public void onBindViewHolder(@NonNull TaskHolder holder, int position) {
    Task currentTask = tasks.get(position);
    holder.a_tname.setText(currentTask.getTname());
    holder.a_tdate.setText(currentTask.getTDate());
    holder.a_ttime.setText(currentTask.getTTime());
    holder.a_tprior.setText(currentTask.getTprior());
    holder.bind(tasks.get(position));
    holder.checkbox.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            holder.bind2(tasks.get(position));
        }
    });
}
 class TaskHolder extends RecyclerView.ViewHolder  {
    private final TextView a_tname;
    private final TextView a_tdate;
    private  final TextView a_ttime;
    private final TextView a_tprior;
    ImageView priorityIndicator;
    CheckBox checkbox;


    public TaskHolder(View itemView) {
        super(itemView);
        a_tname = itemView.findViewById(R.id.a_tname);
        a_tdate=itemView.findViewById(R.id.a_tdate);
        a_ttime = itemView.findViewById(R.id.a_ttime);
        a_tprior = itemView.findViewById(R.id.a_tprior);
        priorityIndicator = itemView.findViewById(R.id.priorityIndicator);
        checkbox = itemView.findViewById(R.id.checkbox);

private void bind2(Task task){
        if(checkbox.isChecked()){
            int checkedtext = ContextCompat.getColor(a_tname.getContext(), R.color.grey);
            a_tname.setTextColor(checkedtext);
            int checkeddate =  ContextCompat.getColor(a_tdate.getContext(), R.color.grey);
            a_tdate.setTextColor(checkeddate);
            int checkedtime = ContextCompat.getColor(a_ttime.getContext(), R.color.grey);
            a_ttime.setTextColor(checkedtime);
            Toast.makeText(checkbox.getContext(), "Way to go! Now swipe to delete", Toast.LENGTH_LONG).show();
        }
        if(!checkbox.isChecked()){
            int untext = ContextCompat.getColor(a_tname.getContext(), R.color.black);
            a_tname.setTextColor(untext);
            int undate = ContextCompat.getColor(a_tdate.getContext(), R.color.black);
            a_tdate.setTextColor(undate);
            int untime = ContextCompat.getColor(a_ttime.getContext(), R.color.black);
            a_ttime.setTextColor(untime);
        }
    }

May i please know how this can be done


Solution

  • Because after closing and opening of your app, your Fragment/Activity calls onCreate again (which follows with the normal lifecycle of fragment methods') creating the fragment from zero, what you need is to store UI data somewhere before closing the app and fetch it later everytime onViewCreated is called, you can store your data in SharedPreferences or using a database like SQLite, Room Database or Firebase.

    incase of SharedPreferences I can give you a quick example on how to use it but I highly recommend you start learning about Room database in case if the data you want to store would be like data structures, then Room will provide you with good ways to store and retrieve your data through what it calls entities.

    1. first, you should get a reference to your SharedPreferences (you can name it anything instead of 'recycleview')
    SharedPreferences shared = getContext().getSharedPreferences("recycleview",Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = shared.edit();
    //when you need to store that a certain item got checked, might put it's position as key
    String posString = Integer.valueOf(position).toString();
    editor.putBoolean("item" + posString ,checkbox.isChecked).apply();
    
    1. and next time when you start the application, when you assign the data to your Adapter, when you bind your view holder to the data, check if there's an old value stored in the sharedPreferences like this :
    SharedPreferences shared = context.getSharedPreferences("recycleview",Context.MODE_PRIVATE);
    String keyString = Integer.valueOf(position).toString();
    checkbox.setChecked(shared.getBoolean("item" + keyString ,false ));
    

    where if the SharedPreferences didn't find a certain key stored in it, it returns the default value that you specified as second parameter to the method getBoolean (which in this case false).

    • you can start reading about Room database from here :

    Accessing data using Room Database| Android Developers

    • you can start reading about SharedPerfreneces from here :

    Save key-value data |Android Developers


    Update

    yes I see it belongs to the recycle view items that's why I said to store it with a key named 'item' + its position string.

    • if your recycler view data is an entity or defined by a unique key and you want to resort to a more complicate way of recycler view selection you can check my other answer here.

    • in the previously mentioned answer, when you're finished with your fragment you would call tracker.getSelection() and check which keys got selected to store them in your database.

    • when you come back to this fragment, you will get what you stored in your database and call tracker.select(key) on all of them, where when the adapter comes to bind some data you would ask it if tracker.isSelected(data.get(i).getKey()) and set the checkbox by the returned boolean value as an example.

    • if you still willing to use the SharedPreferences, you could add an onClickListener to the holder rootView, whenever the user click anywhere in the holder it shall trigger this onClickListener to check its position by using the method holder.getAbsoluteAdapterPosition and using this returned position you would store whether the checkbox is currently checked or not .

    public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
        SharedPreferences shared ;
        SharedPreferences.Editor editor;
     //pass the to the constructor a reference to the SharedPreferences from the Fragment/Activity
        public MyAdapter(SharedPreferences shared, ...other paramters) {
            this.shared= shared;
            this.editor = shared.edit();
        }
        @Override
        public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
             View v = LayoutInflater.from(context).inflate(R.layout.recycler_view_item, parent, false);
             View root = v.getRootView();
             MyViewHolder holder = new MyViewHolder (root);
         root.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int position = holder.getAbsoluteAdapterPosition();
                    //when you need to store that a certain item got checked, might put it's position as key
                    String posString = Integer.valueOf(position).toString();
                    editor.putBoolean("item" + posString, holder.getcheckbox().isChecked).apply();
                }
            });
            return root ;
        }
        
        @Override
        public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
            ...
            boolean isSelected = shared.getBoolean("item" + position,false )
            Checkbox checkbox = holder.getcheckbox();
            checkbox.setChecked(isSelected);
        }
        ...
    }
    

    where holder.getcheckbox() is a method in the view holder that should return the checkbox view