Flutter读取Firestore数据报docs属性无条件访问错误
Firestore 读取数据空安全报错修复
问题背景
读取Firebase Firestore数据时触发空安全报错,相同实现此前可正常运行,已确认Firestore安全规则未拦截数据读取,手动添加空检查后问题未解决。
报错信息
The property 'docs' can't be unconditionally accessed because the receiver can be 'null'.
Try making the access conditional (using '?.') or adding a null check to the target ('!').
原始问题代码
// 原代码存在笔误,类定义关键字少写首字母c,写为lass,正确应为class class Toyota extends StatefulWidget { const Toyota({Key? key}) : super(key: key); @override State<Toyota> createState() => _ToyotaState(); } class _ToyotaState extends State<Toyota> { // 该变量定义后未被使用,属于冗余代码 final firestore = FirebaseFirestore.instance.collection("toyota").get(); @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( body: StreamBuilder( stream: FirebaseFirestore.instance.collection('singers').snapshots(), builder: (context, snapshot) { return ListView.builder( itemCount: (snapshot.data as QuerySnapshot).docs.length, itemBuilder: (context, index) => Text( // 此处直接访问snapshot.data的docs属性触发报错 snapshot.data.docs[index]["price"], ),
问题原因
- 旧版
cloud_firestore未适配Dart空安全,snapshot.data被定义为非空类型,因此旧写法可正常运行;SDK升级到2.0及以上版本后完成空安全适配,snapshot.data为可空类型,在异步请求未完成、请求出错时data值为null,直接访问属性会触发空安全校验报错,并非Firestore数据读取逻辑发生变更。 - 仅在
itemCount位置对snapshot.data做了类型强转,itemBuilder中的属性访问未同步做非空处理,且强转前未校验快照加载状态,加载阶段直接强转会触发类型转换异常。 - 代码存在类关键字笔误、冗余未使用变量的问题。
修复要点
- 给
StreamBuilder指定明确泛型StreamBuilder<QuerySnapshot>,避免隐式类型转换问题 - 访问快照数据前先校验加载状态、错误状态,确认数据返回后再做后续操作
- 确认数据非空后通过
!非空断言统一获取数据快照存为局部变量,避免重复写非空判断逻辑 - 修正类关键字笔误,删除未使用的冗余
firestore变量,读取字段后通过toString()统一转成字符串,适配Text组件的入参类型要求
修复后可运行代码
class Toyota extends StatefulWidget { const Toyota({Key? key}) : super(key: key); @override State<Toyota> createState() => _ToyotaState(); } class _ToyotaState extends State<Toyota> { @override Widget build(BuildContext context) { return SafeArea( child: Scaffold( body: StreamBuilder<QuerySnapshot>( stream: FirebaseFirestore.instance.collection('singers').snapshots(), builder: (context, snapshot) { // 加载状态展示加载组件 if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } // 错误状态展示错误提示 if (snapshot.hasError) { return Center(child: Text('数据加载失败: ${snapshot.error}')); } // 流程走到此处时数据必然非空,可安全访问 final docList = snapshot.data!.docs; return ListView.builder( itemCount: docList.length, itemBuilder: (context, index) { return Text( docList[index]["price"].toString(), ); }, ); }, ), ), ); } }
内容的提问来源于stack exchange,提问作者Mt Khalifa
相关产品推荐
相关产品推荐

