2

I have implemented RecyclerView with FirebaseUI-Android library.

My RecyclerView realtime data change well once i use that FirebaseRecyclerAdapter

In Collection that data document have field type as Boolean , Integer, Reference.

I want use that Reference to get data in populateViewHolder with addSnapshotListener.

Help me! Here is my code:

         FirebaseRecyclerAdapter<Conv, ConvViewHolder> firebaseConvAdapter = new FirebaseRecyclerAdapter<Conv, ConvViewHolder>(
            Conv.class,
            R.layout.users_single_layout,
            ConvViewHolder.class,
            conversationQuery
    ) {
        @Override
        protected void populateViewHolder(final ConvViewHolder convViewHolder, final Conv conv, int i) {

            final String list_user_id = getRef(i).getKey();

            final DocumentReference docRef = db.collection("cities").document(list_user_id);
            docRef.addSnapshotListener(new EventListener<DocumentSnapshot>() {
                @Override
                public void onEvent(@Nullable DocumentSnapshot snapshot,
                                    @Nullable FirebaseFirestoreException e) {
                    if (e != null) {
                        Log.w(TAG, "Listen failed.", e);
                        return;
                    }

                    if (snapshot != null && snapshot.exists()) {
                        Log.d(TAG, "Current data: " + snapshot.getData());
                    } else {
                        Log.d(TAG, "Current data: null");
                    }
                }
            });
        }
    };

    mConvList.setAdapter(firebaseConvAdapter);

Firebase saying if you add addSnapshotListener then must to remove it once no need for that Detach a listener

When you are no longer interested in listening to your data, you must detach your listener so that your event callbacks stop getting called. This allows the client to stop using bandwidth to receive updates. You can use the unsubscribe function on onSnapshot() to stop listening to updates.

Prags
  • 2,457
  • 2
  • 21
  • 38
Pankaj Savaliya
  • 141
  • 1
  • 2
  • 11

2 Answers2

9

To achieve this, you need to use a EventListener<DocumentSnapshot> like this:

EventListener<DocumentSnapshot> eventListener = new EventListener<DocumentSnapshot>() {
    @Override
    public void onEvent(DocumentSnapshot snapshot, FirebaseFirestoreException e) {
        if (snapshot != null && snapshot.exists()) {
            //Do what you need to do
        }
    }
};

Declare a global ListenerRegistration listenerRegistration; variable and add the SnapshotListener in the place where is needed like this:

if (listenerRegistration == null ) {
    listenerRegistration = yourRef.addSnapshotListener(eventListener);
}

To remove the listener, just use the following lines of code, in your onStop() method:

@Override
protected void onStop() {
    if (listenerRegistration != null) {
        listenerRegistration.remove();
    }
}

Also, don't forget to add it again once your onStart() method is called.

@Override
protected void onStart() {
    super.onStart();
    listenerRegistration = yourRef.addSnapshotListener(eventListener);
}

When you are calling addSnapshotListener for listening to realtime updates, it means that you attach a listener that gets called for every change that takes place in your database. So this is happening also when your app is closed, that's why it's mandatory to detach the listeners before the activity gets destroyed.

If in your app you don't need to get the data in realtime, then you can simply use a get() call directly on the reference, which just reads the document only once. Since it only reads once, there is no listener to be removed. This is the correspondent of addListenerForSingleValueEvent() used in the Firebase realtime database.

There is also a more elegant way for removing the listener which is to pass the activity as first the argument in the addSnapshotListener() method, so Firestore can clean up the listeners automatically when the activity is stopped.

ListenerRegistration lg = yourDocumentRef
            .addSnapshotListener(YourActivity.this, eventListener);
Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • I want to use in Item of recycler adapter.and much using bandwidth of firebase while lots of data in adapter with listener. – Pankaj Savaliya Feb 10 '18 at 12:15
  • If you are removing the listener, will be no problems anymore. Have you tried my code? – Alex Mamo Feb 10 '18 at 12:29
  • Yes i have tried already but it's best way or not? because google saying much use of listener cause to much use of bandwidth once lots of data. – Pankaj Savaliya Feb 12 '18 at 05:16
  • Yes, definitely it's the best way! And yes, that's correct, lost of listener can cause to much use of bandwidth, but **only** if you don't remove them. So using the code in my answer, will solve your problem. Do you think that my answer helped you? – Alex Mamo Feb 12 '18 at 05:25
  • Yes. i'm only worry about bandwidth so that's why making question. thanks for your great help. :) – Pankaj Savaliya Feb 12 '18 at 13:17
2

There is also a more elegant way for removing the listener which is to pass the activity as first the argument in the addSnapshotListener() method, so Firestore can clean up the listeners automatically when the activity is stopped. Blockquote

It was very important. I did not search for "elegant way", but it was hint why my listener stops sometimes. I removed activity field, and now listener not stopping without my direct instruction in case of activity state changing.