Flutter中如何仅显示包含消息的聊天室
隐藏无消息聊天室的解决方案
我正在跟着教程开发基础聊天App,当前代码会展示所有聊天室(无论是否包含消息)。我希望隐藏无消息的聊天室(例如清空所有消息后,该聊天室不再显示在首页),但不清楚该在何处添加where子句,以及如何统计消息数量。相关代码如下:
class ChatRoomModel { String? chatroomid; Map<String, dynamic>? participants; String? lastMessage; DateTime? lastmessagetime; ChatRoomModel({this.chatroomid, this.participants, this.lastMessage,this.lastmessagetime}); ChatRoomModel.fromMap(Map<String, dynamic> map) { chatroomid = map["chatroomid"]; participants = map["participants"]; lastMessage = map["lastmessage"]; lastmessagetime = map["lastmessagetime"].toDate(); } Map<String, dynamic> toMap() { return { "chatroomid": chatroomid, "participants": participants, "lastmessage": lastMessage, "lastmessagetime":lastmessagetime, }; } }
Container( child: StreamBuilder( stream: FirebaseFirestore.instance .collection("chatrooms") .where("participants.${widget.usermodel.uid}", isEqualTo: true) .snapshots(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.active) { if (snapshot.hasData) { QuerySnapshot querysnapshot = snapshot.data as QuerySnapshot; return Padding( padding: const EdgeInsets.symmetric(horizontal: 10,vertical: 10), child: ListView.builder( itemCount: querysnapshot.docs.length, itemBuilder: (context, index) { ChatRoomModel chatroommodel = ChatRoomModel.fromMap( querysnapshot.docs[index].data() as Map<String, dynamic>); Map<String, dynamic> parties = chatroommodel.participants!; List<String> listofpartieskey = parties.keys.toList(); listofpartieskey.remove(widget.usermodel.uid); //todo futurebuilder to be studied return FutureBuilder( future: getuserdatabyid(listofpartieskey[0]), builder: (context, userdata) {```
方案一:利用现有lastMessage字段过滤(高效优先)
你的ChatRoomModel已经包含lastMessage字段,只需在Firestore查询阶段直接过滤掉无消息的聊天室即可,无需额外统计:
修改StreamBuilder的stream查询逻辑:
stream: FirebaseFirestore.instance .collection("chatrooms") .where("participants.${widget.usermodel.uid}", isEqualTo: true) .where("lastmessage", isNotEqualTo: null) // 过滤无最后消息的聊天室 .where("lastmessage", isNotEqualTo: "") // 额外过滤空字符串场景 .snapshots(),
配套操作
清空聊天室所有消息时,记得同步更新该聊天室的lastMessage为null:
await FirebaseFirestore.instance .collection("chatrooms") .doc(chatroomId) .update({ "lastmessage": null, "lastmessagetime": null, // 可选,同步清空时间字段 });
这个方案性能最优,Firestore可直接通过索引完成过滤,无需额外查询。
方案二:精确统计消息数量过滤(严谨但性能稍弱)
如果需要严格判断聊天室是否存在任何消息(比如lastMessage字段可能存在异常值),可以在渲染每个聊天室前查询消息子集合的文档数量:
修改ListView的itemBuilder逻辑:
itemBuilder: (context, index) { ChatRoomModel chatroommodel = ChatRoomModel.fromMap( querysnapshot.docs[index].data() as Map<String, dynamic>); Map<String, dynamic> parties = chatroommodel.participants!; List<String> listofpartieskey = parties.keys.toList(); listofpartieskey.remove(widget.usermodel.uid); // 新增:查询当前聊天室的消息总数 return FutureBuilder<int>( future: FirebaseFirestore.instance .collection("chatrooms") .doc(chatroommodel.chatroomid) .collection("messages") // 替换为你实际的消息子集合名称 .get() .then((snap) => snap.docs.length), builder: (context, messageCountSnapshot) { if (messageCountSnapshot.connectionState == ConnectionState.waiting) { return SizedBox(height: 60); // 加载占位UI } // 消息数量为0时,不渲染该项 if (messageCountSnapshot.data == 0) { return SizedBox.shrink(); } // 原有的用户信息查询逻辑 return FutureBuilder( future: getuserdatabyid(listofpartieskey[0]), builder: (context, userdata) { // 你的原有UI渲染代码 }, ); }, ); },
注意
- 该方案每个聊天室都会发起一次独立查询,当聊天室数量较多时,会增加Firestore读取次数,影响性能和成本。
- 优先推荐方案一,同时确保消息操作时的数据一致性。
内容的提问来源于stack exchange,提问作者Irfan Ganatra
相关产品推荐
相关产品推荐

