Flutter使用StreamBuilder时触发空值检查运算符错误
错误信息
The following _CastError was thrown building StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(dirty, state: _StreamBuilderBaseState<DocumentSnapshot<Map<String, dynamic>>, AsyncSnapshot<DocumentSnapshot<Map<String, dynamic>>>>#65942):
Null check operator used on a null value
我已经针对ConnectionState.none、ConnectionState.waiting以及!streamSnapshot.hasData状态设置了CircularProgressIndicator,但问题依然存在。
我的StreamBuilder代码如下:
return StreamBuilder( stream: FirebaseFirestore.instance .collection("users") .doc(FirebaseAuth.instance.currentUser!.uid) .snapshots(), builder: (context, streamSnapshot) { var userData = streamSnapshot.data!; if (streamSnapshot.connectionState == ConnectionState.none || streamSnapshot.connectionState == ConnectionState.waiting) { return const Center( child: CircularProgressIndicator(color: darkblueColor), ); } if (!streamSnapshot.hasData) { return const Center( child: CircularProgressIndicator(color: darkblueColor), ); } return ListView( padding: EdgeInsets.zero, children: [ UserAccountsDrawerHeader( accountName: Text(userData['applicationStatus'] == "none" ? 'Display Name' : userData['displayName']), accountEmail: Text(userData['applicationStatus'] == "none" ? "Your profile not yet published." : userData['phoneNumber']), currentAccountPicture: CircleAvatar( backgroundColor: whiteColor, child: ClipOval( child: Image.network( userData['applicationStatus'] == "none" ? '..........' : userData['imageUrl'], fit: BoxFit.cover, width: 90, height: 90, ), ), ), decoration: BoxDecoration( color: appBarColor,), ), ListTile( leading: Icon(Icons.account_circle), title: Text('Profile'), onTap: () => null, ), ], ); });
问题根源
你在判断连接状态和数据存在性之前,就直接用streamSnapshot.data!取数据并赋值给userData了。这时候如果streamSnapshot.data是null(比如初始加载、网络波动导致快照暂时无数据),强制解包的!就会触发Null check错误。
修复方案
把var userData = streamSnapshot.data!;移到所有状态判断之后,确保只有在确认有数据时才去获取数据。另外,还要额外判断streamSnapshot.data是否为null(比如文档不存在的情况),避免后续取值出错。
修正后的代码:
return StreamBuilder( stream: FirebaseFirestore.instance .collection("users") .doc(FirebaseAuth.instance.currentUser!.uid) .snapshots(), builder: (context, streamSnapshot) { // 先处理加载状态 if (streamSnapshot.connectionState == ConnectionState.none || streamSnapshot.connectionState == ConnectionState.waiting) { return const Center( child: CircularProgressIndicator(color: darkblueColor), ); } // 处理无数据或数据为null的情况 if (!streamSnapshot.hasData || streamSnapshot.data == null) { return const Center( child: CircularProgressIndicator(color: darkblueColor), ); } // 确认有数据后再赋值 var userData = streamSnapshot.data!; return ListView( padding: EdgeInsets.zero, children: [ UserAccountsDrawerHeader( accountName: Text(userData['applicationStatus'] == "none" ? 'Display Name' : userData['displayName'] ?? 'Display Name'), // 额外处理displayName为null的情况 accountEmail: Text(userData['applicationStatus'] == "none" ? "Your profile not yet published." : userData['phoneNumber'] ?? "No phone number"), // 处理phoneNumber为null的情况 currentAccountPicture: CircleAvatar( backgroundColor: whiteColor, child: ClipOval( child: Image.network( userData['applicationStatus'] == "none" // 替换为默认头像的合法URL ? 'https://via.placeholder.com/90' : userData['imageUrl'] ?? 'https://via.placeholder.com/90', // 处理imageUrl为null的情况 fit: BoxFit.cover, width: 90, height: 90, ), ), ), decoration: BoxDecoration(color: appBarColor), ), ListTile( leading: Icon(Icons.account_circle), title: Text('Profile'), onTap: () => null, ), ], ); });
额外优化建议
- 避免直接使用
FirebaseAuth.instance.currentUser!.uid,可以先判断currentUser是否为null,比如:final currentUser = FirebaseAuth.instance.currentUser; if (currentUser == null) { // 处理未登录状态,比如跳转到登录页 return LoginPage(); } // 再获取stream stream: FirebaseFirestore.instance.collection("users").doc(currentUser.uid).snapshots(), - 对Firestore文档中的字段取值时,使用
??提供默认值,避免字段不存在时触发Null错误。
内容的提问来源于stack exchange,提问作者Rokey Z

