5

Below is the code I used to retrieve documents data in a recyclerview. It works fine. But whenever the new document is added, it does not update it in real time. I know snapshot listener is for that purpose only but having a hard time to get it work. Any help will be appreciated. :)

 mFirestore.collection("Users").get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
            @Override
            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                if (task.isSuccessful()){
                    for (DocumentSnapshot document : task.getResult()) {
                        Message message = document.toObject(Message.class);
                        messageList.add(message);
                        mAdapter.notifyDataSetChanged();
                    }
                }
            }
        });
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Ashish Yadav
  • 543
  • 2
  • 7
  • 30
  • 2
    If you are interested, **[this](https://stackoverflow.com/questions/49277797/how-to-display-data-from-firestore-in-a-recyclerview-with-android/49277842)** is a recommended way in which you can retrieve data from a Cloud Firestore database and display it in a `RecyclerView` using `FirestoreRecyclerAdapter`. – Alex Mamo Jul 15 '18 at 11:17
  • Thanks Alex. Will try this – Ashish Yadav Jul 16 '18 at 15:06
  • @AlexMamo fireStoreRecycelerAdapter doesn't support multiple layout inflator. So your answer is not applied in all cases. – Vikash Sharma Oct 03 '19 at 14:56
  • @VikashSharma please see my answer without using FirestoreRecyclerAdapter – DragonFire Mar 12 '20 at 14:07
  • I think that this [resource](https://medium.com/firebase-tips-tricks/how-to-effortlessly-get-real-time-updates-from-firestore-on-android-bcb823f45f20) will help. – Alex Mamo Mar 28 '23 at 15:49

4 Answers4

12

you should separate the snapshot event like this.. then you can easily find out, what's the problem

mFirestore.collection("Users")
        .addSnapshotListener(new EventListener<QuerySnapshot>() {
            @Override
            public void onEvent(@Nullable QuerySnapshot snapshots,
                                @Nullable FirebaseFirestoreException e) {
                if (e != null) {
                    Log.w("TAG", "listen:error", e);
                    return;
                }

                for (DocumentChange dc : snapshots.getDocumentChanges()) {
                    switch (dc.getType()) {
                        case ADDED:
                            Log.d("TAG", "New Msg: " + dc.getDocument().toObject(Message.class));
                            break;
                        case MODIFIED:
                            Log.d("TAG", "Modified Msg: " + dc.getDocument().toObject(Message.class));
                            break;
                        case REMOVED:
                            Log.d("TAG", "Removed Msg: " + dc.getDocument().toObject(Message.class));
                            break;
                    }
                }

            }
        });

Maybe the snapshot you got, was triggered by [MODIFIED] event, not [ADDED]..

Howard Chen
  • 229
  • 3
  • 8
2

If you want to keep listening your Firestore data (realtime update), you should do like this:

mFirestore.collection("Users")
            .addSnapshotListener(new EventListener<QuerySnapshot>() {
                @Override
                public void onEvent(@Nullable QuerySnapshot queryDocumentSnapshots,
                                    @Nullable FirebaseFirestoreException e) {

                    if (e != null) {
                        Log.w("YourTag", "Listen failed.", e);
                        return;
                    }

                    for (QueryDocumentSnapshot doc : queryDocumentSnapshots) {
                        if (doc.exists()){
                            Message message = doc.toObject(Message.class);
                            messageList.add(message);
                            mAdapter.notifyDataSetChanged();
                        }
                    }
                    Log.d("YourTag", "messageList: " + messageList);
                }
            });

the way you use only retrieve Firestore data once.

Check this >> https://firebase.google.com/docs/firestore/query-data/listen

Howard Chen
  • 229
  • 3
  • 8
0

Please see how to use it in recycler view:

// Get Chats List From FireStore
private void getChatListFromFireBase(String hiddenStatus) {

    lIndividualChatList = new ArrayList<>();
    lIndividualChatListIds = new ArrayList<>();

    lIndividualChatList.clear();
    lIndividualChatListIds.clear();

    fbFs.collection("individual_chats")
        .document(mySqlUserId)
        .collection("lists")
        .addSnapshotListener(new EventListener<QuerySnapshot>() {
            @Override
            public void onEvent(QuerySnapshot documentSnapshots,
                                FirebaseFirestoreException e) {

                if (e != null) {

                }

                for (DocumentChange dc : documentSnapshots.getDocumentChanges()) {
                    switch (dc.getType()) {
                        case ADDED:

                            key = dc.getDocument()
                                    .getId();

                            firebaseRetrofitQuery(dc,
                                                  "Added",
                                                  key);

                            break;
                        case MODIFIED:

                            key = dc.getDocument()
                                    .getId();

                            // Do The Change Function
                            firebaseRetrofitQuery(dc,
                                                  "Changed",
                                                  key);

                            break;
                        case REMOVED:

                            break;
                    }
                }

            }
        });
}



// FireBase And Retrofit Query
private void firebaseRetrofitQuery(DocumentChange documentChange,
                                   final String childActivityType,
                                   final String key) {

    if (childActivityType.equals("Added")) {

        lIndividualChatListIds.add(key);

    }

    // Get The Receiver Id To Get Data From Other Nodes
    final String mySqlFriendUserId = documentChange.getDocument()
                                                   .getId();

    final String hideStatus = (String) documentChange.getDocument()
                                                     .getData()
                                                     .get("hide_status");

    if (childActivityType.equals("Added")) {

        // Populate The Array List With Data From Both Nodes
        lIndividualChatList.add(new IndividualListModel(mySqlFriendUserId,
                                                        hideStatus));

    }

    if (childActivityType.equals("Changed")) {

        int index = lIndividualChatListIds.indexOf(key);
        lIndividualChatList.set(index,
                                new IndividualListModel(mySqlFriendUserId,
                                                        hideStatus));

    }

    // Use The Adapter To Populate The Recycler View
    aIndividualChatList = new IndividualListAdapter(getContext(),
                                                    lIndividualChatList,
                                                    senderActivity,
                                                    new IndividualListAdapter.OnItemClickListener() {

                                                        @Override
                                                        public void onItemClicked(final Map data) {

                                                        }
                                                    });
    rvList.setAdapter(aIndividualChatList);

    aIndividualChatList.notifyDataSetChanged();

}
DragonFire
  • 3,722
  • 2
  • 38
  • 51
0

You can get the latest user list when added to firebase by removing the logged In user as we don't want to display the currently logged user in the list. And remove duplicate records to show them as a list in the adapter.

// Fetch real time record from firebase and remove duplicate values from list

    userPreferences.uuid.asLiveData().observe(requireActivity(), Observer {
        FirebaseHelper().fireStoreDatabase.collection(NODE_USERS)
            .addSnapshotListener(EventListener<QuerySnapshot> { value, error ->
                if (error != null || value == null) {
                    return@EventListener
                }
                for (record in value) {
                    if (record.exists()) {
                        // remove duplicate records
                        userArrayList.removeIf {
                            it.id == record[KEY_ID]
                        }

                        // Get list of user excluding loggedIn user by checking UUID with id
                        if (record.data[KEY_ID].toString() != it) {
                            userArrayList.add(
                                User(
                                    record[KEY_ID].toString(),
                                    record[KEY_NAME].toString(),
                                    record[KEY_IS_ONLINE].toString(),
                                    record[KEY_TIME_STAMP].toString()
                                )
                            )
                            friendListAdapter.notifyDataSetChanged()
                        }
                    }
                }
            })
    })

Data class is as below

data class User(val id: String, val name: String, val status: String,val timestamp: String)
Nk P
  • 41
  • 4