1

I have tab layout (3 fragments) with recyclerview and checkboxes for every fragment. I set up onClickListener, but after I exit my app, checkbox statuses are reseted. I tried some solutions I found online some solutions (about shared preferences) but neither work for me. Maybe I implement it wrong. Can you help me ?

Also if need, I can share with you my Fragment file.

recyclerview java:

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

    Context mContext;
    List<RecTab1> mData;

    public RecyclerViewAdapter(Context mContext, List<RecTab1> mData) {
        this.mContext = mContext;
        this.mData = mData;
    }
    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View v ;
        v = LayoutInflater.from(mContext).inflate(R.layout.item_tab1,parent,false);
        MyViewHolder vHolder = new MyViewHolder(v);
        return vHolder;
    }
    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {

        holder.tv_name.setText(mData.get(position).getName());
        holder.tv_subName.setText(mData.get(position).getSubName());
        holder.cb_checkbox.setChecked(mData.get(position).getSelected());
        holder.cb_checkbox.setTag(position);
        holder.cb_checkbox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Integer pos = (Integer) holder.cb_checkbox.getTag();
                Toast.makeText(mContext, mData.get(pos).getName() + " clicked!", Toast.LENGTH_LONG).show();
                if (mData.get(pos).getSelected()) {
                    mData.get(pos).setSelected(false);
                } else {
                    mData.get(pos).setSelected(true);
                }
            }
        });
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }
    public static class MyViewHolder extends RecyclerView.ViewHolder{

        private TextView tv_name;
        private TextView tv_subName;
        private CheckBox cb_checkbox;

        public MyViewHolder (View itemView){
            super (itemView);
            tv_name = (TextView) itemView.findViewById(R.id.Item1Name);
            tv_subName = (TextView) itemView.findViewById(R.id.Item1SubName);
            cb_checkbox = (CheckBox) itemView.findViewById(R.id.CheckboxID);
        }
    }
}

item java:

public class RecTab1 {
    private String Name;
    private String SubName;
    private boolean isSelected;

    public RecTab1(){
    }
    public RecTab1 (String name, String subName){
        Name = name;
        SubName = subName;
    }
    public String getName() {
        return Name;
    }
    public String getSubName() {
        return SubName;
    }
    public void setName(String name) {
        Name = name;
    }
    public void setSubName(String subName) {
        SubName = subName;
    }
    public boolean getSelected() {
        return isSelected;
    }
    public void setSelected(boolean selected) {
        isSelected = selected;
    }
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Zvezda Bre
  • 61
  • 4
  • See this link : https://stackoverflow.com/questions/3624280/how-to-use-sharedpreferences-in-android-to-store-fetch-and-edit-values?page=1&tab=votes#tab-top – cgb_pandey Jun 06 '20 at 08:43
  • I found this before, but I don't know how to implement in my app because I have Fragment and Recyclerview adapter and I don't know where should I place code. – Zvezda Bre Jun 06 '20 at 12:41
  • Since, you want to customize views that are inside the `viewholder`, you need to put this code inside the `adapter` class. Listen for `checkChanged` event of those `checkbox` inside your `ViewHolder` class and set current `checked` info using `SharedPreferences`. Then retrieve it later inside `onBindViewHolder()` method. – cgb_pandey Jun 06 '20 at 13:08
  • I can't handle it. I am trying all day. Thanks anyway. – Zvezda Bre Jun 06 '20 at 20:02

1 Answers1

0

There are basically 2 kinds of persistence:

  • Temporary persistence (Scope: can be only used inside Activity/Fragment)
  • Long-term persistence (Scope: goes beyond the lifecycle of Activity/Fragment)

I think, you implemented first technique by creating Rect1 object somewhere(I assumed you did not save them in the database as I did not see those lines of code) and later trying to access the values when needed elsewhere. But, those variables will be destroyed and recreated later on destroying and recreating of the fragment when you would switch between tabs in your TabLayout.
What you need is the second one.
There are many versions of this kind of persistence as :
- SharedPreferences
- Sqlite Database
- Online Database such as Firebase
For eg: In your case, if you have few numbers of tabs which again has few numbers of information to persist then, you can use SharedPreferences. If there is larger number of tabs and in turn larger number of information to persist then, using Sqlite Database is better. See this link about using Room to save data in Sqlite

Now using SharedPreferences, you can save the checked state of the CheckBox into the preference file in the onCheckChangedListener method as:

public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(mContext).inflate(R.layout.item_tab1, parent, false);
    Checkbox cb_checkbox = v.findViewById(R.id.CheckboxID);
    cb_checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    mContext.getSharedPreferences("com.example.yourapp.SAVED_STATE", Context.MODE_PRIVATE)  
                        .edit()  
                        .putBoolean("cb_checkbox", isChecked)
                        .apply();
                }
            });

I set the onCheckChangedListener in the onCreateViewHolder because mContext was available. You could have also done in inside the MyViewHolder class passing the Context object in the constructor of MyViewHolder.It is NOT recommended to set listener in onBindViewHolder() because it is called multiple times during binding so, there would be recurrent setting of listener even for those cb_checkbox in the MyViewHolder object whose listeners are already set.

Now, to retrieve the checked state of the cb_checkbox, we will see in our SharedPreferences to find information if it is saved previously as :

            @Override
            public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
                // your other binding code
                // code for binding previous state of the checkbox if is saved otherwise false as a default 
                boolean checkedState = mContext.getSharedPreferences("com.example.yourapp.SAVED_STATE", MODE_PRIVATE)
                        .getBoolean("cb_checkbox", false);
                holder.cb_checkbox.setChecked(checkedState);
            }
cgb_pandey
  • 985
  • 1
  • 11
  • 18