0

I'm using firebase snapshot listener on my adapter. And, whenever the value updates the adapter is updated. But the problem is it tries to update even when the activity is destroyed.
It is crashing at Glide.with(holder.itemView.getContext()) and the error is You cannot start a load for a destroyed activity

Yes, there are lots of related questions on stackoverflow. Must of them aren't possible in adapter. I also tried recyclerView.setAdapter(null), recyclerView.removeAllViewsInLayout() on my fragment but none is working.

Simplified adapter Code

 @Override
protected void onBindViewHolder(@NonNull final ChatHolder holder, int position, @NonNull final MessageClass model) {

    final FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();


    firebaseFirestore.collection("users").document(model.getUser_receiver())
            .addSnapshotListener(new EventListener<DocumentSnapshot>() {
                @Override
                public void onEvent(@Nullable DocumentSnapshot queryDocumentSnapshots, @Nullable FirebaseFirestoreException e) {
                    if (queryDocumentSnapshots != null) {

                            ProfileClass profileClass = queryDocumentSnapshots.toObject(ProfileClass.class);
                                 String userId = queryDocumentSnapshots.getString("user_uid");

                            if(userId != null) {

                                    if (profileClass.getUser_image().equals("image")) {
                                        Glide.with(holder.itemView.getContext()).load(R.drawable.profile_image).into(holder.roundedImageViewChatsItemChatsImage);

                                    } else {
                                        Glide.with(holder.itemView.getContext()).load(profileClass.getUser_image()).into(holder.roundedImageViewChatsItemChatsImage);

                                    }
                                }
                                }

                        }

            });

Logs

Java.lang.IllegalArgumentException: 
at com.bumptech.glide.manager.RequestManagerRetriever.assertNotDestroyed 
 (RequestManagerRetriever.java:323)
 at com.bumptech.glide.manager.RequestManagerRetriever.get (RequestManagerRetriever.java:132)
 at com.bumptech.glide.manager.RequestManagerRetriever.get (RequestManagerRetriever.java:116)
 at com.bumptech.glide.Glide.with (Glide.java:707)
 at com.meeti.all.Chats.ChatsFirestore$1.onEvent (ChatsFirestore.java:111)
 at com.meeti.all.Chats.ChatsFirestore$1.onEvent (ChatsFirestore.java:64)
 at com.google.firebase.firestore.DocumentReference.zza (SourceFile:497)
 at com.google.firebase.firestore.zzd.onEvent (Unknown Source:6)
 at com.google.firebase.firestore.g.zzh.zza (SourceFile:28)
 at com.google.firebase.firestore.g.zzi.run (Unknown Source:6)
 at android.os.Handler.handleCallback (Handler.java:873)
 at android.os.Handler.dispatchMessage (Handler.java:99)
 at android.os.Looper.loop (Looper.java:201)
 at android.app.ActivityThread.main (ActivityThread.java:6823)
 at java.lang.reflect.Method.invoke (Native Method)
 at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:547)
 at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:873)

I'm banging my head around this for a week.
Please help.
Thanks

Md. Asaduzzaman
  • 14,963
  • 2
  • 34
  • 46
Sushan Niroula
  • 119
  • 1
  • 1
  • 8

2 Answers2

2

You're requesting context of from itemView, but for asynchronous calls you should use app context, because context of view/fragment might not be available after the execution of that asynchronous call (in your case Glide image loading request).

To fix this issue, simply replace

holder.itemView.getContext() 

with

holder.itemView.getContext().getApplicationContext()
Harsh Jatinder
  • 833
  • 9
  • 15
1

Option - 1: As you need the data only once, you can use get() like below:

firebaseFirestore
    .collection("users")
    .document(model.getUser_receiver())
    .get()
    .addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
        @Override
        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
            if(task.isSuccessful()) {
                DocumentSnapshot documentSnapshot = task.getResult();

                //Rest of your code
            }
        }
    });

Option - 2: Add your context to addSnapshotListener like below:

firebaseFirestore
    .collection("users")
    .document(model.getUser_receiver())
    .addSnapshotListener(
        holder.itemView.getContext(), 
        new EventListener<DocumentSnapshot>() 
            {

            });

As stated in official documentation:

Starts listening to this query using an Activity-scoped listener.
The listener will be automatically removed during onStop().

Md. Asaduzzaman
  • 14,963
  • 2
  • 34
  • 46