Reputation: 877
I am making a chat activity using Firebase to store messages and a RecyclerView
to display them. Per the below adapter costructor, when the RecyclerView
is initialized, the last 50 messages are queried from Cloud Firestore and arranged in descending order by a Unix timestamp. I then use setStackFromEnd(true) in my chat activity to flip the order they are displayed in, as the newest messages should be near the bottom, and new messages are added to the adapter's message list using messageList.add(0,message)
This presents a problem. In onBindViewHolder, the previously acceptable:
Message message = messageList.get(position);
holder.message.setText(message.getMessage());
holder.author.setText(message.getAuthor() + ":");
No longer works because the message being entered into the RecyclerView will be a repeat of the most recent message when the RecyclerView is loaded(the one in position 0). i.e.:
Instead of:
Where "message one" is the most recent message when the RecyclerView
is created. Replacing this with:
Message message = messageList.get(0);
holder.message.setText(message.getMessage());
holder.author.setText(message.getAuthor() + ":");
In onBindViewHolder
to get the true most recent message will have it appear on the screen, but also subsequently replace all items with the most recent message when they are recycled. Ultimately I'd like to have queried messages listed bottom to top in order of recency, while continuing to place the newest messages toward the bottom(like every chat app ever), without having to query an entire collection. Where should I correct my mistake and how?
Adapter Constructor:
public ChatRecyclerViewAdapter(Context mContext, ArrayList<String> mMessage, ArrayList<String> mAuthor, String mRoomID, FirebaseFirestore firestore) {
messageList = new ArrayList<>();
firestore = FirebaseFirestore.getInstance();
mCollection = firestore.collection(mRoomID + "_messages");
Query query = mCollection.orderBy("timestamp", Query.Direction.DESCENDING).limit(50);
query.addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(@Nullable QuerySnapshot queryDocumentSnapshots, @Nullable FirebaseFirestoreException e) {
for (DocumentChange documentChange : queryDocumentSnapshots.getDocumentChanges()) {
switch (documentChange.getType()) {
case ADDED:
documentChange.getDocument();
Message message = documentChange.getDocument().toObject(Message.class);
messageList.add(0,message);
notifyItemInserted(messageList.size());
}
}
}
});
Attempt at querying next oldset set of messages on scroll:
query.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
if (queryDocumentSnapshots.size() > 0) {
//Get the last visible document
DocumentSnapshot lastVisible = queryDocumentSnapshots.getDocuments().get(messageList.size()-1);
//Construct a new query starting at this document and get the next batch of messages
Query next = mCollection.orderBy("timestamp", Query.Direction.DESCENDING).startAfter(lastVisible).limit(20);
next.get();
}
}
});
Upvotes: 1
Views: 82
Reputation: 139019
The problem in your code is that you are sorting in descending order by using a Unix timestamp
and not using a Date
object. To make it work, I recommend you change the way you are storing the timestamp to a Date. For that, please see my answer from this post, where I have explained how you can achieve this using either a POJO class
or using a Map
.
Here you can find a tutorial on how to can create a Chat App, where I have explained the exact same thing that you are looking for. Please see the screenshot below:
In my code I have used as a query, the following line of code:
val query = rootRef!!
.collection("messages")
.document(roomId)
.collection("roomMessages")
.orderBy("sentAt", Query.Direction.ASCENDING)
Upvotes: 1