andrewedgar
andrewedgar

Reputation: 877

Insert object at beginning of a RecyclerView displaying Firebase query

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

Answers (1)

Alex Mamo
Alex Mamo

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:

enter image description here

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

Related Questions