The Fluffy T Rex
The Fluffy T Rex

Reputation: 600

Order of ArrayList changes when updating from Firestore Database

Problem: My list items display in the wrong order. This happens when I close the fragment and re-open it. It then displays all the "sent messages" first, and then the received messages after. However, when I'm in writing the messages, they appear in the correct order. It's only when I close the fragment/activity and re-open it that the order has changed.

I call the getMessages method in my on-create method for opening the fragment containing the view.

What I've tried:

Question:

Here is my main "getMessages" method:

public void getLiveChatMessages(final ArrayList<ChatConversationMessage> messageArrayList, final ChatConversationAdapter adapter, final String matchClicked) {

    final String userID = onboardingFirebaseUser.returnCurrentUserId();

    final CollectionReference messagesCollectionRef = db.collection("users")
            .document(userID)
            .collection("matches")
            .document(matchClicked)
            .collection("messages");

    messagesCollectionRef
            .orderBy("TimeStamp", Query.Direction.DESCENDING)
            .addSnapshotListener(new EventListener<QuerySnapshot>() {
                                     @Override
                                     public void onEvent(@Nullable QuerySnapshot value,
                                                         @Nullable FirebaseFirestoreException e) {
                                         if (e != null) {
                                             Log.w(TAG, "listen:error", e);
                                             return;
                                         }


                                         for (QueryDocumentSnapshot doc : value) {
                                             if (doc.get("Message") != null) {

                                                 if (doc.get("Message") != null && doc.get("From user with ID").equals(userID)) {
                                                     String message = doc.getString("Message");

                                                     messageArrayList.add(new ChatConversationMessage(message));
                                                     adapter.notifyDataSetChanged(); //Ensures messages are visible immediately

                                                 } else if (doc.get("Message") != null) {
                                                     final String message = doc.getString("Message");

                                                     DocumentReference matchRef = db.collection("users")
                                                             .document(userID)
                                                             .collection("matches")
                                                             .document(matchClicked);

                                                     matchRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
                                                         @Override
                                                         public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                                                             if (task.isSuccessful()) {
                                                                 DocumentSnapshot document = task.getResult();
                                                                 if (document.exists()) {
                                                                     imageReference = storageReference.child(document.getString("profileImg"));
                                                                     messageArrayList.add(new ChatConversationMessage(message, imageReference));
                                                                     adapter.notifyDataSetChanged(); //Ensures messages are visible immediately

                                                                 } else {
                                                                     Log.d(TAG, "No such document");
                                                                 }
                                                             } else {
                                                                 Log.d(TAG, "get failed with ", task.getException());
                                                             }
                                                         }
                                                     });

                                                 }
                                             }
                                         }
                                     }
                                 });}}

Upvotes: 0

Views: 815

Answers (1)

The Fluffy T Rex
The Fluffy T Rex

Reputation: 600

After some time I've found the problem.

I was calling a the get-method on a new reference within the snapshot listener. When you do this, it impacts the order of the items in your ArrayList.

To solve it, ensure that all the items you need from Firestore to create your ArrayList is stored in the same location as fields on each document (and not in two different locations). That way, you don't need to use a separate get-method on a new reference within a snapshot listener. This also keeps client-side code cleaner. For future Googlers, here is how I restructured my method:

messagesCollectionRef
            .orderBy("TimeStamp", Query.Direction.ASCENDING)
            .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 message added" + dc.getDocument().getData());

                                if (dc.getDocument().get("Message") != null && dc.getDocument().get("From user with ID").equals(userID)) {
                                    String message = dc.getDocument().getString("Message");
                                    messageArrayList.add(new ChatConversationMessage(CURRENTUSER, message, null));
                                    adapter.notifyDataSetChanged();
                                }

                                if (dc.getDocument().get("Message") != null && dc.getDocument().get("From user with ID").equals(matchClicked)) {
                                    String message = dc.getDocument().getString("Message");
                                    imageReference = storageReference.child(dc.getDocument().getString("profileImg"));
                                    messageArrayList.add(new ChatConversationMessage(OTHERUSER, message, imageReference));
                                    adapter.notifyDataSetChanged();
                                }
                                break;
                            case MODIFIED:
                                break;
                            case REMOVED:
                                break;
                        }
                    }
                }
            });

As you can see, I've now stored the imageReference String within each message doc in Firestore, and it can be retrieved in the same way I retrieve all the other data I need to make an addition to my ArrayList. The major code change you need to do is where you write your data to the cloud (ie. write/set Firestore docs). That's where you'll need to make sure that everything is added as field values to your doc, so you don't need to get it in separate locations. Good luck!

Upvotes: 0

Related Questions