StreamBuilder传入DocumentSnapshot流时Snapshot返回null数据问题
Flutter StreamBuilder 加载单个DocumentSnapshot流时数据始终为null的问题
在Flutter开发中,使用StreamBuilder监听Firebase Firestore单个DocumentSnapshot的流时,snapshot始终返回null数据。已添加连接状态与数据检查,但界面一直显示“No Profile Data”。相关代码如下:
UserModel.dart
import 'package:cloud_firestore/cloud_firestore.dart'; class UserModel { String? earningsUnit; String? email; String? fullName; String? lastUpdate; String? profileImageUrl; String? superAdmin; String? totalPoints; String? totalWorkMinutes; String? uid; String? updatedBy; UserModel({ this.earningsUnit, this.email, this.fullName, this.lastUpdate, this.profileImageUrl, this.superAdmin, this.totalPoints, this.totalWorkMinutes, this.uid, this.updatedBy, }); factory UserModel.fromDocumentSnapshot(Map<String,dynamic> data) { return UserModel( earningsUnit: data.containsKey("earningsUnit") ? data["earningsUnit"] ?? "" : "", email: data.containsKey("email") ? data["email"] ?? "" : "", fullName: data.containsKey("fullname") ? data["fullname"] ?? "" : "", lastUpdate: data.containsKey("lastupdate") ? data["lastupdate"] ?? false : false, profileImageUrl: data.containsKey("profileImageUrl") ? data["profileImageUrl"] ?? 0 : 0, superAdmin: data.containsKey("superAdmin") ? data["superAdmin"] ?? 0 : 0, totalPoints: data.containsKey("totalPoints") ? data["totalPoints"] ?? 0 : 0, totalWorkMinutes: data.containsKey("totalWorkMinutes") ? data["totalWorkMinutes"] ?? "" : "", uid: data.containsKey("uid") ? data["uid"] ?? "" : "", updatedBy: data.containsKey("updatedby") ? data["updatedby"] ?? "" : "", ); } }
UserNetwork.dart
class UserNetwork { final FirebaseFirestore _db = FirebaseFirestore.instance; Stream<UserModel> retrieveUserData(String id) { final stream = _db.collection('users').doc(id).snapshots(); return stream.map((snap) => UserModel.fromDocumentSnapshot(snap.data()!)); } }
StreamBuilder实现
StreamBuilder( stream: userNetwork .retrieveUserData(FirebaseAuth.instance.currentUser!.uid), builder: (BuildContext context, snapshot) { if (snapshot.connectionState == ConnectionState.active) { if (snapshot.data != null) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), child: Text( snapshot.data!.fullName ?? "", style: const TextStyle( fontWeight: FontWeight.w900, fontSize: 25, ), ), ), InkWell( onTap: () { Navigator.pushNamed(context, EditProfile.id); }, child: Container( padding: const EdgeInsets.fromLTRB(0, 0, 20, 0), child: CircleAvatar( backgroundImage: NetworkImage(snapshot.data!.profileImageUrl!), radius: 40, ), ), ), ], ); } else { return Center( child: Text( 'No Profile Data', style: cTextStyleMedium, ), ); } } return Center( child: CustomLoading(), ); }, ),

问题排查与解决方案
1. 修复DocumentSnapshot强制解包风险
在UserNetwork的retrieveUserData方法中,直接使用snap.data()!强制解包会在文档不存在或加载失败时抛出异常,导致流中断。需先判断文档是否存在:
Stream<UserModel?> retrieveUserData(String id) { final stream = _db.collection('users').doc(id).snapshots(); return stream.map((snap) { if (snap.exists) { return UserModel.fromDocumentSnapshot(snap.data()!); } else { return null; // 文档不存在时返回null } }); }
2. 修正UserModel类型不匹配错误
UserModel工厂构造函数中存在多处类型不匹配问题,会导致模型初始化失败:
lastUpdate为String类型,却设置布尔值false为默认值profileImageUrl、superAdmin、totalPoints为String类型,却设置数字0为默认值
修正后的工厂构造函数:
factory UserModel.fromDocumentSnapshot(Map<String,dynamic> data) { return UserModel( earningsUnit: data.containsKey("earningsUnit") ? data["earningsUnit"] ?? "" : "", email: data.containsKey("email") ? data["email"] ?? "" : "", fullName: data.containsKey("fullname") ? data["fullname"] ?? "" : "", lastUpdate: data.containsKey("lastupdate") ? data["lastupdate"] ?? "" : "", profileImageUrl: data.containsKey("profileImageUrl") ? data["profileImageUrl"] ?? "" : "", superAdmin: data.containsKey("superAdmin") ? data["superAdmin"] ?? "" : "", totalPoints: data.containsKey("totalPoints") ? data["totalPoints"] ?? "" : "", totalWorkMinutes: data.containsKey("totalWorkMinutes") ? data["totalWorkMinutes"] ?? "" : "", uid: data.containsKey("uid") ? data["uid"] ?? "" : "", updatedBy: data.containsKey("updatedby") ? data["updatedby"] ?? "" : "", ); }
3. 完善StreamBuilder异常处理
当前代码未处理流中的异常(如权限不足、网络错误),需添加错误捕获逻辑:
builder: (BuildContext context, snapshot) { if (snapshot.hasError) { return Center(child: Text('加载失败: ${snapshot.error}')); } if (snapshot.connectionState == ConnectionState.active) { if (snapshot.data != null) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), child: Text( snapshot.data!.fullName ?? "", style: const TextStyle( fontWeight: FontWeight.w900, fontSize: 25, ), ), ), InkWell( onTap: () { Navigator.pushNamed(context, EditProfile.id); }, child: Container( padding: const EdgeInsets.fromLTRB(0, 0, 20, 0), child: CircleAvatar( backgroundImage: NetworkImage(snapshot.data!.profileImageUrl ?? ""), radius: 40, ), ), ), ], ); } else { return Center( child: Text( 'No Profile Data', style: cTextStyleMedium, ), ); } } return Center(child: CustomLoading()); },
4. 额外检查项
- 确认Firebase Auth的
currentUser不为null,避免强制解包报错:final currentUser = FirebaseAuth.instance.currentUser; if (currentUser == null) { return Text('请先登录'); } // 再使用currentUser.uid调用retrieveUserData - 验证Firestore中
users集合存在对应UID的文档,且字段名与代码中一致(如fullname是小写) - 确认Firestore权限规则允许当前用户读取该文档
内容的提问来源于stack exchange,提问作者Shahroz Javed
相关产品推荐
相关产品推荐

