0

I am using a RecyclerView to display a list of activities saved in my Firebase database. I have added a checkbox to the layout of the activity view so that the user can select whether they want to add this activity to their audit profile.

When the user clicks the checkbox to select the activity, I want to add this activity to their profile (which is stored in a separate table) and update a field in the original activity table to say that it is now included in the audit profile. When they uncheck the box, it is removed from their profile and the original activity is updated to reflect this.

However, when I try doing this, my checkboxes start behaving incorrectly (such as a checkbox being checked that definitely hasn't been clicked by the user, checkboxes not staying ticked). This only happens when I have both the code to add the activity to the profile and to update the original activity.

Any ideas? I think it might be something to do with state, but I'm not sure how to go about doing this.

My code is as follows

 auditAdapter = new FirestoreRecyclerAdapter<Activity, AuditBuilder.AuditViewHolder>(auditBuilder) {
        @Override
        protected void onBindViewHolder(@NonNull final AuditBuilder.AuditViewHolder auditViewHolder, int i, @NonNull final Activity activity) {

            auditViewHolder.aAuditActivityName.setText(activity.getActivity_Name());
            auditViewHolder.aAuditActivityType.setText(activity.getActivity_Type());
            auditViewHolder.aAuditActivityDate.setText(activity.getActivity_Date());

            final String docId = auditAdapter.getSnapshots().getSnapshot(i).getId();

            auditViewHolder.auditCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    if (isChecked){

                        //ADD DOCUMENT ID TO DATABASE
                        DocumentReference documentReference = fStore.collection("audits")
                                .document(user.getUid())
                                .collection("myAuditActivities")
                                .document(docId);


                        Map<String, Object> audit = new HashMap<>();

                        audit.put("Activity_ID", docId);
                        audit.put("Activity_Name", activity.getActivity_Name());
                        audit.put("Activity_Description", activity.getActivity_Description());
                        audit.put("Activity_Type", activity.getActivity_Type());
                        audit.put("Activity_Date", activity.getActivity_Date());
                        audit.put("Activity_Hours", activity.getActivity_Hours());
                        audit.put("Activity_Mins", activity.getActivity_Mins());
                        audit.put("Activity_Ref1", activity.getActivity_Ref1());
                        audit.put("Activity_Ref2", activity.getActivity_Ref2());
                        audit.put("Activity_Ref3", activity.getActivity_Ref3());
                        audit.put("Activity_Ref4", activity.getActivity_Ref4());
                        audit.put("Image_URL", activity.getImage_URL());
                        audit.put("In_Audit", true);

                        documentReference.set(audit).addOnSuccessListener(new OnSuccessListener<Void>() {
                            @Override
                            public void onSuccess(Void aVoid) {
                                Log.d("TAG", "Activity successfully added to audit");
                            }
                        }).addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Toast.makeText(AuditBuilder.this, "Error, try again", Toast.LENGTH_SHORT).show();
                            }
                        });


                        //UPDATE BOOLEAN IN_AUDIT IN CPD ACTIVITIES LOCATION IN DATABASE TO TRUE
                        DocumentReference updateActivity = fStore.collection("cpdActivities")
                                .document(user.getUid())
                                .collection("myCPD")
                                .document(docId);

                        Map<String, Object> updateBoolean = new HashMap<>();
                        updateBoolean.put("In_Audit", true);

                        updateActivity.update(updateBoolean).addOnSuccessListener(new OnSuccessListener<Void>() {
                            @Override
                            public void onSuccess(Void aVoid) {
                                Log.d("TAG", "In_Audit successfully updated");
                            }
                        }).addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Log.d("TAG", "In_Audit update failed");
                            }
                        });

                    } else {
                        //CHECKBOX UNCHECKED, DELETES FROM AUDIT TABLE
                        DocumentReference docRef = fStore.collection("audits")
                                .document(user.getUid())
                                .collection("myAuditActivities")
                                .document(docId);
                        docRef.delete().addOnSuccessListener(new OnSuccessListener<Void>() {
                            @Override
                            public void onSuccess(Void aVoid) {
                                Log.d("TAG", "Activity successfully removed from audit");
                            }
                        }).addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Toast.makeText(AuditBuilder.this, "Error, try again", Toast.LENGTH_SHORT).show();
                            }
                        });


                        //UPDATE BOOLEAN IN_AUDIT IN CPD ACTIVITIES LOCATION IN DATABASE BACK TO FALSE
                        DocumentReference updateActivity = fStore.collection("cpdActivities")
                                .document(user.getUid())
                                .collection("myCPD")
                                .document(docId);

                        Map<String, Object> updateBoolean = new HashMap<>();
                        updateBoolean.put("In_Audit", false);

                        updateActivity.update(updateBoolean).addOnSuccessListener(new OnSuccessListener<Void>() {
                            @Override
                            public void onSuccess(Void aVoid) {
                                Log.d("TAG", "In_Audit successfully updated");
                            }
                        }).addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                Log.d("TAG", "In_Audit update failed");
                            }
                        });


                    }
                }
            });


            auditViewHolder.view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent i = new Intent(v.getContext(), ActivityDetails.class);
                    //DISPLAYS ALL THE ATTRIBUTES OF THE ACTIVITY
                    i.putExtra("Activity_Name", activity.getActivity_Name());
                    i.putExtra("Activity_Description", activity.getActivity_Description());
                    i.putExtra("Activity_Type", activity.getActivity_Type());
                    i.putExtra("Activity_Date", activity.getActivity_Date());
                    i.putExtra("Activity_Hours", activity.getActivity_Hours());
                    i.putExtra("Activity_Mins", activity.getActivity_Mins());
                    i.putExtra("Activity_Ref1", activity.getActivity_Ref1());
                    i.putExtra("Activity_Ref2", activity.getActivity_Ref2());
                    i.putExtra("Activity_Ref3", activity.getActivity_Ref3());
                    i.putExtra("Activity_Ref4", activity.getActivity_Ref4());
                    i.putExtra("Image_URL", activity.getImage_URL());
                    i.putExtra("Activity_ID", docId);
                    v.getContext().startActivity(i);
                }
            });



        }

        @NonNull
        @Override
        public AuditBuilder.AuditViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.auditbuilder_view_layout, parent,false);
            return new AuditViewHolder(view);
        }
    };

To try fixing this problem, I have added a boolean (In_Audit) to my model as follows:

public class Activity {
private String Activity_Name; 
etc
private boolean In_Audit;

public Activity(String name, String date, String hours, String minutes, String description, String ref1, String ref2, String ref3, String ref4, String type, String image_URL, boolean In_Audit){
    this.Activity_Name = Activity_Name;
    this.Activity_Date = Activity_Date;
    this.Activity_Hours = Activity_Hours;
    this.Activity_Mins = Activity_Mins;
    this.Activity_Description = Activity_Description;
    this.Activity_Ref1 = Activity_Ref1;
    this.Activity_Ref2 = Activity_Ref2;
    this.Activity_Ref3 = Activity_Ref3;
    this.Activity_Ref4 = Activity_Ref4;
    this.Activity_Type = Activity_Type;
    this.Image_URL = Image_URL;
    this.In_Audit = false;
}


public boolean isIn_Audit() {
    return In_Audit;
}

public void setIn_Audit(boolean in_Audit) {
    In_Audit = in_Audit;
}

}

I have then referenced this in my onBindViewHolder like this

auditAdapter = new FirestoreRecyclerAdapter<Activity, AuditBuilder.AuditViewHolder>(auditBuilder) {
        @Override
        protected void onBindViewHolder(@NonNull final AuditBuilder.AuditViewHolder auditViewHolder, int i, @NonNull final Activity activity) {

            auditViewHolder.aAuditActivityName.setText(activity.getActivity_Name());
            auditViewHolder.aAuditActivityType.setText(activity.getActivity_Type());
            auditViewHolder.aAuditActivityDate.setText(activity.getActivity_Date());
            auditViewHolder.auditCheckBox.setSelected(activity.isIn_Audit());

            final String docId = auditAdapter.getSnapshots().getSnapshot(i).getId();




            auditViewHolder.auditCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    if (isChecked){
                        activity.setIn_Audit(true);

                    } else {
                        activity.setIn_Audit(false);}});
                     

But I am still having errors with my check boxes, such as without scrolling, my checking my first checkbox and it not staying clicked. I'm not 100% sure I have applied the above logic correctly however.

smose
  • 145
  • 1
  • 11
  • You have not talked about scrolling. Do they hold their value at scrolling? – blackapps Jul 29 '20 at 13:07
  • No, they don't hold value correctly while scrolling. For example. when I navigate to the activity, nothing should be checked but if I scroll down, one will already be checked. – smose Jul 30 '20 at 10:19
  • Then first solve the scrolling issue before you do anything else. – blackapps Jul 30 '20 at 10:21
  • I've attempted a few fixes on this with no success unfortunately. I have tried adding a boolean to my model to try keep track of the checkbox status then using this in my onBindViewHolder but my checkboxes don't persist when if I haven't scrolled – smose Jul 30 '20 at 12:16
  • Adding a boolean (a boolean for every checkbox) to your model is indeed the way to go. That should work. – blackapps Jul 30 '20 at 12:19
  • I've updated my main question with what I've tried but it's still not working - I'm not sure if I have applied the logic correctly. What do you think? – smose Jul 30 '20 at 13:46
  • `if (isChecked){ activity.setIn_Audit(true);` You cannot use that activity variable here as it is long gone when the user touches a checkbox. You should first discover the item position of the checkbox and then use a function like setInAudit(position, isChecked); to change the boolean in the right model in the model array. – blackapps Jul 30 '20 at 13:58
  • Unfortunately I'm not further with figuring this out - I've tried applying some of the proposed solutions from this question https://stackoverflow.com/questions/32427889/checkbox-in-recyclerview-keeps-on-checking-different-items but I'm not sure how to discover the item position of the checkbox. Could you explain how I can go about doing this please? – smose Jul 31 '20 at 15:05
  • I will not explain as i have no code at hand at the moment. But as you are #325 to ask about checkboxes in a list with scrolling there have been many answers on stackoverflow already. So i reacon you will find them. – blackapps Jul 31 '20 at 15:53
  • Haha that is true, there does seem to be a lot of questions on this topic and I've read quite a few of them and tested various things but still not having any success! I will keep trying however. A lot of the questions are not about Firestore RecyclerViews and I'm not sure if this makes a difference? – smose Aug 01 '20 at 08:52
  • You should start with a simple recycle view with only a text and a checkbox per item. Take a new activity to try it out. Keep it simple. First try to get the scrolling ok. After that rotate your phone to see if all stays the same at rotation. Solve all first before you continue with the firestore one. All is pretty elementary and once solved you can grab it for your following projects. – blackapps Aug 01 '20 at 08:57

0 Answers0