Stream返回空列表但所有打印语句均正常输出的问题排查
问题分析与修复方案
你的问题核心是异步执行顺序错误,导致返回Stream时retVal还没被填充数据:
rooms.forEach是异步遍历Firestore的Stream事件,而getOtherUser又是异步请求,你在这些异步操作还没完成时就直接返回了Stream.value(retVal),此时retVal还是空数组。- 另外,Firestore的
snapshots()本身就是一个Stream,你应该直接转换这个Stream,而不是手动遍历后返回静态Stream。
修改方案
用asyncMap处理Firestore的snapshot流,确保每个snapshot对应的所有异步请求完成后,再把处理好的列表发射到Stream中:
Stream<List<RoomsListModel>>? roomsListStream() { try { print("userId: $userId"); // 直接返回转换后的Firestore snapshot流 return FirebaseFirestore.instance .collection("rooms") .where("users", arrayContains: userId) .orderBy("latestMessageTime", descending: true) .snapshots() .asyncMap((snapshot) async { List<RoomsListModel> retVal = []; // 遍历当前snapshot的所有文档,等待每个getOtherUser请求完成 for (var doc in snapshot.docs) { print("element: $doc"); var room = doc.data(); print("room: $room"); var roomId = room["roomId"]; var otherUserId = room["users"].firstWhere((element) => element != userId); var lastMessage = room["latestMessage"]; var lastMessageTime = room["latestMessageTime"]; print("otherUserId: $otherUserId"); // 用await等待异步请求完成,确保数据被添加到retVal var value = await getOtherUser(otherUserId); print("value: $value"); var avatar = value["photoUrl"]; var name = value["name"]; retVal.add(RoomsListModel( roomId: roomId, otherUserId: otherUserId, avatar: avatar, name: name, lastMessage: lastMessage, lastMessageTime: lastMessageTime, )); } // 所有文档处理完成后,返回填充好的列表 return retVal; }); } catch (e) { print("Error: $e"); return null; } }
关键修改点
- 用
asyncMap替代原有的forEach,这样能把每个Firestore snapshot转换成异步处理后的列表。 - 把
forEach换成for循环并使用await,确保每个getOtherUser请求完成后再处理下一个文档,保证retVal被正确填充。 - 直接返回转换后的Firestore Stream,而不是创建一个静态的
Stream.value(retVal)。
这样修改后,Stream会在每次Firestore数据更新时,自动发射处理完成的RoomsListModel列表,你就能正常访问到数据了。
内容的提问来源于stack exchange,提问作者cipano
相关产品推荐
相关产品推荐

