Stream报错NoSuchMethodError:在null上调用[]方法,求解决方案
Stream 抛出 NoSuchMethodError: The method '[]' was called on null 问题分析与修复
问题描述
使用Stream时遇到错误:NoSuchMethodError: The method '[]' was called on null,添加打印语句后输出的data内容正常,但Stream仍返回该错误。
打印的data结果:
{ userId1: 59jTMEbvqFd8C8UhInksauAVNk63, userId2: 2ssfDEPhPhcIwInUWdlm0ReH5RZ2, latestMessageTime: Timestamp(seconds=1667140814, nanoseconds=334000000), lastMessageSenderId: 59jTMEbvqFd8C8UhInksauAVNk63, created_at: 2022-10-26 19:44:13.793275, latestMessage: TEST 3, roomId: Qv30s8kATJbFJIWRdBEo }
相关代码:
roomsStream 方法
Stream<RoomsListModel> roomsStream() async* { try { var rooms = await FirebaseFirestore.instance.collection("rooms") .where("users", arrayContains: userId) .orderBy("latestMessageTime", descending: true) .snapshots(); print("rooms: $rooms"); await for (var room in rooms) { for (var doc in room.docs) { var data = doc.data() as Map<String, dynamic>; print("data: $data"); var otherUser = await getOtherUser(data["users"][0] == userId ? data["users"][1] : data["users"][0]); print("otherUser: $otherUser"); yield RoomsListModel( roomId: doc.id, userId: otherUser["user id"], avatar: otherUser["photoUrl"], name: otherUser["name"], lastMessage: data["latestMessage"], lastMessageTime: data["latestMessageTime"] ); } } } catch (e) { print("Error: $e"); } }
getOtherUser 方法
Future getOtherUser(String id) async { var user = await FirebaseFirestore.instance.collection("users") .doc(id) .get() .then((value) => value.data()) as Map<String, dynamic>; return user; }
错误原因
- 字段不匹配:打印的
data中仅包含userId1、userId2字段,不存在代码中访问的users数组,直接调用data["users"][0]等同于在null上调用[]方法,触发错误。 - 用户文档空值未处理:
getOtherUser中强制将value.data()转为Map<String, dynamic>,若指定ID的用户文档不存在,value.data()返回null,强制类型转换会抛出异常;即便转换成功,后续访问otherUser["user id"]等字段时,若otherUser为null也会触发该错误。 - 异常捕获不完整:
getOtherUser内部的异常未被捕获,一旦执行出错会直接中断Stream的执行。
修复方案
1. 修正字段访问逻辑
因为实际数据中存储的是userId1和userId2而非users数组,调整获取另一用户ID的逻辑:
// 替换原获取otherUser的代码行 String otherUserId = data["userId1"] == userId ? data["userId2"] : data["userId1"]; var otherUser = await getOtherUser(otherUserId);
2. 完善getOtherUser的空值处理
避免用户文档不存在时返回null或抛出异常,同时调整返回类型确保类型安全:
Future<Map<String, dynamic>?> getOtherUser(String id) async { var docSnapshot = await FirebaseFirestore.instance.collection("users").doc(id).get(); if (!docSnapshot.exists) { print("用户文档不存在,ID: $id"); return null; // 也可返回预设的默认用户信息 } return docSnapshot.data() as Map<String, dynamic>?; }
3. 在Stream中添加空值校验
创建RoomsListModel前先检查otherUser是否为null,避免后续字段访问报错:
if (otherUser != null) { yield RoomsListModel( roomId: doc.id, userId: otherUser["user id"], avatar: otherUser["photoUrl"], name: otherUser["name"], lastMessage: data["latestMessage"], lastMessageTime: data["latestMessageTime"] ); } else { print("无法获取用户信息,跳过该房间: ${doc.id}"); }
4. 扩大异常捕获范围
将单个房间文档的处理逻辑也纳入try-catch,避免单个房间处理失败导致整个Stream终止:
await for (var room in rooms) { for (var doc in room.docs) { try { var data = doc.data() as Map<String, dynamic>; print("data: $data"); String otherUserId = data["userId1"] == userId ? data["userId2"] : data["userId1"]; var otherUser = await getOtherUser(otherUserId); print("otherUser: $otherUser"); if (otherUser != null) { yield RoomsListModel( roomId: doc.id, userId: otherUser["user id"], avatar: otherUser["photoUrl"], name: otherUser["name"], lastMessage: data["latestMessage"], lastMessageTime: data["latestMessageTime"] ); } } catch (e) { print("处理房间文档失败: ${doc.id}, 错误: $e"); } } }
内容的提问来源于stack exchange,提问作者cipano
相关产品推荐
相关产品推荐

