Flutter ListView调用snapshot.data时空值检查操作符作用于空值报错
报错原因
- 状态判断顺序错误:错误状态、加载状态的判断逻辑被放在了
snapshot.data != null的分支内部,且该分支的map操作无任何返回值,代码无论是否进入该分支,都会直接执行最后的ListView渲染逻辑。 - 空值场景未做拦截:当Stream处于初始状态、加载中状态时,
snapshot.data为null,此时ListView中直接使用!强制拆包空值,直接触发空安全报错。 - 存在无效冗余代码:
snapshot.data != null分支内的遍历逻辑既没有赋值也没有返回,属于完全不生效的死代码,没有起到任何状态拦截作用。
修复方案
调整状态判断的优先级,先处理错误、加载场景,确认数据非空后再渲染列表,修复后的完整代码如下:
body: StreamBuilder<QuerySnapshot?>( stream: _usersStream, builder: (BuildContext context, AsyncSnapshot<QuerySnapshot?> snapshot) { // 优先处理错误状态 if (snapshot.hasError) { return const Text('Something went wrong'); } // 处理加载中状态 if (snapshot.connectionState == ConnectionState.waiting) { return const Center( child: CircularProgressIndicator(), ); } // 处理无数据的空状态 if (!snapshot.hasData || snapshot.data == null) { return const Center(child: Text('暂无数据')); } // 走到此处已经保证snapshot.data非空,使用!不会报错 return ListView( children: snapshot.data!.docs.map((DocumentSnapshot document) { // 可额外添加document.data的空判断,避免后续强制拆包风险 Map<String, dynamic>? data = document.data() as Map<String, dynamic>?; if (data == null) return const SizedBox.shrink(); return InkWell( child: Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0)), child: Container( child: Column( children: [ Container( width: double.infinity, height: 260.0, decoration: BoxDecoration( color: Colors.blue, image: DecorationImage( image: NetworkImage(data['images'][0]), fit: BoxFit.cover, ), borderRadius: const BorderRadius.only( topLeft: Radius.circular(15), topRight: Radius.circular(15),), ) ), ListTile( title: Text(data['catName']), ), ], ), ), ), onTap: () { print(data['id']); Navigator.push( context, MaterialPageRoute( builder: (context) => PostBook(id: data['id']))); }, ); }).toList(), ); }, ),
额外优化:对document.data()的返回值也增加了空判断,避免文档数据为空时触发同样的空安全报错。
内容的提问来源于stack exchange,提问作者Muhammad Arslan
相关产品推荐
相关产品推荐

