You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Firestore的onComplete方法中对ArrayList进行排序?

解决Firestore异步查询导致消息列表乱序的问题

问题根源

你遇到的问题核心是Firestore的get()请求是异步执行的,循环中发起的多个用户信息请求的完成顺序不固定,导致直接往ArrayList里add数据时,顺序被打乱——先完成的请求会先把数据加入列表,不管它原本在排序后的消息列表里的位置。

解决方案:绑定消息与用户信息的对应关系

不要用多个独立的ArrayList分别存储消息、时间戳、用户信息,而是创建一个自定义模型类,把每条消息的所有相关数据封装在一起,同时保留原消息列表的排序顺序。

步骤1:定义消息数据模型类

public class MessageInfo {
    private String message;
    private long timestamp; // 可根据你实际使用的日期类型调整
    private String senderName;
    private String senderId;

    // 构造方法
    public MessageInfo(String message, long timestamp, String senderId) {
        this.message = message;
        this.timestamp = timestamp;
        this.senderId = senderId;
    }

    // setter & getter
    public void setSenderName(String senderName) {
        this.senderName = senderName;
    }

    public String getMessage() { return message; }
    public long getTimestamp() { return timestamp; }
    public String getSenderName() { return senderName; }
    public String getSenderId() { return senderId; }
}

步骤2:修改查询逻辑,保留排序顺序

先把排序后的消息数据存入有序列表,再针对每条消息发起用户信息查询,将结果填充到对应位置的模型对象中:

firebaseFirestore.collection(threads).orderBy(timestamp).addSnapshotListener(new EventListener<QuerySnapshot>() {
    @Override
    public void onEvent(@Nullable QuerySnapshot value, @Nullable FirebaseFirestoreException error) {
        if (value == null) return;
        
        int totalMessages = value.size();
        List<MessageInfo> messageList = new ArrayList<>(totalMessages);
        int completedCount = 0;

        // 按排序顺序初始化消息列表,填充已知数据
        for (int i = 0; i < totalMessages; i++) {
            QueryDocumentSnapshot document = value.getDocuments().get(i);
            String message = document.getString("message");
            long timestamp = document.getLong("timestamp"); // 按实际字段类型调整
            String senderId = document.getString("senderId");
            messageList.add(new MessageInfo(message, timestamp, senderId));
        }

        // 循环发起用户信息查询,填充到对应位置的模型中
        for (int i = 0; i < totalMessages; i++) {
            int finalIndex = i;
            MessageInfo currentMsg = messageList.get(i);
            
            firebaseFirestore.collection("users").document(currentMsg.getSenderId()).get()
                    .addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
                        @Override
                        public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                            if (task.isSuccessful() && task.getResult() != null) {
                                String senderName = task.getResult().getString("firstName");
                                currentMsg.setSenderName(senderName);
                            }

                            // 所有请求完成后更新RecyclerView
                            if (++completedCount == totalMessages) {
                                recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
                                adapter = new AdapterRecyclerViewThreads(getActivity(), titleThreads, ThreadsId,
                                        extractSenderNames(messageList), extractUserImages(messageList), extractTimestamps(messageList), getAnswer);
                                recyclerView.setAdapter(adapter);
                            }
                        }
                    });
        }
    }
});

// 辅助方法:从MessageInfo列表中提取适配器需要的字段
private List<String> extractSenderNames(List<MessageInfo> messageList) {
    List<String> names = new ArrayList<>();
    for (MessageInfo msg : messageList) {
        names.add(msg.getSenderName());
    }
    return names;
}

private List<Long> extractTimestamps(List<MessageInfo> messageList) {
    List<Long> timestamps = new ArrayList<>();
    for (MessageInfo msg : messageList) {
        timestamps.add(msg.getTimestamp());
    }
    return timestamps;
}

// 同理实现extractUserImages等方法

为什么这个方法有效

  1. 首先按orderBy(timestamp)的顺序初始化了messageList,保证列表的基础顺序是正确的。
  2. 每个用户信息查询完成后,会把数据填充到messageList中对应的位置,不会改变列表的整体顺序。
  3. 只有当所有异步请求都完成后,才会把数据传递给适配器,此时所有消息的用户信息都已填充完毕,且顺序和最初排序的消息列表一致。

额外优化建议

如果用户信息不会频繁变更,可以考虑本地缓存用户信息,避免每次加载消息都重复查询用户集合,提升性能同时减少Firestore读取次数。

内容的提问来源于stack exchange,提问作者Marcel Sanchez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 21:25:24