如何判断Firestore的Snapshot Listener已完成?
判断Firestore数据获取/监听完成的两种场景
你提到的代码用的是Firestore的一次性数据获取(get()),而如果是实时的Snapshot Listener,判断完成的方式会有区别,我分开给你讲:
1. 针对你当前的一次性获取代码(get())
你现在用的get().addOnCompleteListener()本身就是用来监听这次数据获取任务完成的回调:
- 当
onComplete方法被触发时,不管任务成功还是失败,这次一次性数据获取已经完成了。 - 你代码里有个小问题:
if (task.getResult().isEmpty())放在for循环里面是无效的,因为如果结果为空,for循环根本不会执行,应该把这个判断放在for循环外面,修正后的代码示例:
db.collection("groups").document(id.get(i)).collection("members") .get() .addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() { @Override public void onComplete(@NonNull Task<QuerySnapshot> task) { if (task.isSuccessful()) { QuerySnapshot result = task.getResult(); // 先判断结果是否为空 if (result.isEmpty()) { Log.d(Tag, "没有找到成员数据"); return; } // 遍历处理所有数据 for (QueryDocumentSnapshot document : result) { id.add(document.getId()); Log.e(Tag, document.getId() + " => " + document.getData()); } // 走到这里,说明所有数据都已经处理完成,任务彻底结束 Log.d(Tag, "一次性数据获取并处理完成"); } else { Log.e(Tag, "数据获取失败", task.getException()); // 失败也算任务完成,只是结果异常 } } });
简单说:onComplete回调触发 = 这次get()任务完成,成功的话在遍历完所有文档后,就是你处理完数据的节点。
2. 针对实时Snapshot Listener(addSnapshotListener())
如果你用的是实时监听(需要实时同步数据变化),这种情况下listener会多次触发:第一次是初始加载所有匹配的文档,之后每次数据变化都会触发。要判断初始加载完成,可以通过标记位或者元数据辅助判断,示例代码:
// 标记是否完成初始加载 private boolean isInitialLoadComplete = false; // 添加实时监听 ListenerRegistration listener = db.collection("groups").document(id.get(i)).collection("members") .addSnapshotListener(new EventListener<QuerySnapshot>() { @Override public void onEvent(@Nullable QuerySnapshot value, @Nullable FirebaseFirestoreException error) { if (error != null) { Log.e(Tag, "监听出错", error); return; } if (value != null) { if (!isInitialLoadComplete) { // 第一次触发,处理全部初始数据 for (QueryDocumentSnapshot document : value) { id.add(document.getId()); Log.e(Tag, document.getId() + " => " + document.getData()); } // 标记初始加载完成 isInitialLoadComplete = true; Log.d(Tag, "初始数据加载完成,之后将监听数据变化"); } else { // 后续触发,处理数据更新 Log.d(Tag, "数据发生变化,处理更新"); // 可以通过getDocumentChanges()获取具体的变化类型 for (DocumentChange dc : value.getDocumentChanges()) { switch (dc.getType()) { case ADDED: Log.d(Tag, "新增文档: " + dc.getDocument().getData()); break; case MODIFIED: Log.d(Tag, "修改文档: " + dc.getDocument().getData()); break; case REMOVED: Log.d(Tag, "删除文档: " + dc.getDocument().getData()); break; } } } } } });
如果需要更严谨地判断初始加载是否拿到了服务器最新数据(不是本地缓存),可以结合value.getMetadata().isFromCache():如果该值为false,说明是从服务器获取的完整初始数据,这时候标记初始加载完成会更准确。
内容的提问来源于stack exchange,提问作者Reeman Adel
相关产品推荐
相关产品推荐

