【问题标题】:Insert object at beginning of a RecyclerView displaying Firebase query在显示 Firebase 查询的 RecyclerView 开头插入对象
【发布时间】:2019-03-10 09:58:00
【问题描述】:

我正在使用 Firebase 存储消息并使用 RecyclerView 进行聊天活动来显示它们。根据下面的适配器构造函数,当 RecyclerView 初始化时,会从 Cloud Firestore 查询最后 50 条消息,并按 Unix 时间戳降序排列。然后我在我的聊天活动中使用 setStackFromEnd(true) 来翻转它们的显示顺序,因为最新消息应该靠近底部,并且使用 messageList.add(0,message)

这带来了一个问题。在onBindViewHolder中,之前可以接受的:

Message message = messageList.get(position);

holder.message.setText(message.getMessage());
holder.author.setText(message.getAuthor() + ":");

不再起作用,因为在 RecyclerView 加载时,输入到 RecyclerView 的消息将重复最近的消息(位置 0 的消息)。即:

  • 留言一
  • 留言一
  • 留言一
  • 留言一

代替:

  • 留言一
  • 消息二
  • 消息三
  • 消息四

其中“消息一”是创建RecyclerView 时的最新消息。将其替换为:

Message message = messageList.get(0);

holder.message.setText(message.getMessage());
holder.author.setText(message.getAuthor() + ":");

onBindViewHolder 中获取真正的最新消息将其显示在屏幕上,但随后在回收时将所有项目替换为最新消息。最终,我希望将查询的消息按新近的顺序从下到上列出,同时继续将最新消息放在底部(就像每个聊天应用程序一样),而不必查询整个集合。我应该在哪里纠正我的错误以及如何纠正?

适配器构造函数:

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());
                    }
                }
            }
        });

尝试在滚动时查询下一组旧消息:

 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();
                }
            }
        });

【问题讨论】:

    标签: java android firebase android-recyclerview google-cloud-firestore


    【解决方案1】:

    您的代码中的问题是您使用Unix timestamp 而不是使用Date 对象按降序排序。为了使其工作,我建议您更改将时间戳存储为日期的方式。为此,请参阅我的回答 post,我已经解释了如何使用 POJO class 或使用 Map 来实现这一点。

    您可以在此处找到有关如何创建 Chat App 的教程,其中我已经解释了您正在寻找的完全相同的内容。请看下面的截图:

    在我用作查询的代码中,以下代码行:

    val query = rootRef!!
        .collection("messages")
        .document(roomId)
        .collection("roomMessages")
        .orderBy("sentAt", Query.Direction.ASCENDING)
    

    【讨论】:

    • 抱歉,我遗漏了一些重要的细节。我最终希望能够对消息进行分页 per the documentation 以便在用户滚动到最旧的消息时获取更多信息。我已经为上面添加了我的代码的开头。我按降序排序,以便在我使用 .limit() 时最先加载最新消息。使用限制升序排序会加载最旧的消息,仅此而已,最旧的消息位于位置 [0],在加载时始终可见。
    • 让我们一次只回答一个问题。这听起来是一个新问题,基本上应该被视为另一个无法在评论中回答的问题。为了遵守本社区的规则,请再发一个新问题,以便我和其他用户可以帮助您。
    • 作为个人提示,this 是一种推荐的方式,您可以通过将查询游标与 limit() 方法相结合来对查询进行分页。我还建议您看看这个 video 以获得更好的理解。
    • 如果您认为我的回答和建议对您有所帮助,请考虑接受 (✔️) 我的回答并投票 (?)。我会很感激的。谢谢!
    • 谢谢。如果我仍然遇到问题,我会尝试并发布一个新问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-24
    相关资源
    最近更新 更多