Reputation: 600
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:
orderby
method (both with String and TimeStamp)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
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