Flutter访问Cloud Firestore报无documents getter实例错误排查
报错原因
Class '_JsonQuerySnapshot' has no instance getter 'documents' 是cloud_firestore 2.0及以上版本API不兼容导致的:旧版本QuerySnapshot通过documents属性返回文档列表,新版本该属性已被废弃,统一改用docs获取文档数组。
你的代码除了属性名用错之外,还有几处逻辑错误,仅替换属性名无法正常运行:
- 错误套用HTTP接口请求逻辑处理Firestore返回值:
snapshots()返回的是Stream对象,调用.get()得到的是结构化的QuerySnapshot,不存在body字段,不需要用json.decode转码 - 取值逻辑错误:
docs是List<QueryDocumentSnapshot>类型的数组,不能直接当作Map通过['quote']读取字段,需要先获取单个文档实例,再从文档的data()返回的Map中取对应字段 - 实时流、一次性请求、StreamController混用导致逻辑冗余,你需要的双击切换下一条名言效果,不需要每次操作都重新请求流,首次加载拉取全量名言到本地列表,维护索引切换即可,响应速度更快也能减少读写消耗。
- 原有代码中
_streamController未初始化,运行时会直接抛空指针异常。
修复后可运行代码
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; class MyQuoteApp extends StatefulWidget { final String title; MyQuoteApp({required this.title}); @override _MyQuoteAppState createState() => _MyQuoteAppState(); } class _MyQuoteAppState extends State<MyQuoteApp> { String _imageUrl = "https://source.unsplash.com/random/"; int counter = 0; final FirebaseFirestore _firestore = FirebaseFirestore.instance; // 本地缓存名言列表 List<QueryDocumentSnapshot> _quotesList = []; // 当前展示的名言索引 int _currentQuoteIndex = 0; bool _isLoading = true; // 刷新随机背景图 void _newImage() { setState(() { _imageUrl = 'https://source.unsplash.com/random/$counter'; counter++; }); } // 首次加载拉取全量名言数据 Future<void> _loadQuotes() async { setState(() { _isLoading = true; }); try { QuerySnapshot quoteSnapshot = await _firestore.collection("quotes").get(); _quotesList = quoteSnapshot.docs; _newImage(); } catch (e) { print("名言加载失败: $e"); } finally { setState(() { _isLoading = false; }); } } // 双击切换下一条名言 void _nextQuote() { if (_quotesList.isEmpty) return; setState(() { // 到列表末尾后自动回到第一条 _currentQuoteIndex = (_currentQuoteIndex + 1) % _quotesList.length; }); _newImage(); } @override void initState() { super.initState(); _loadQuotes(); } @override Widget build(BuildContext context) { SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]); return Scaffold( backgroundColor: Colors.black26, appBar: AppBar( title: Center(child: Text(widget.title)), ), body: Center( child: _isLoading ? const Center(child: Text("正在加载名言.....")) : _quotesList.isEmpty ? const Center(child: Text("暂无名言数据")) : GestureDetector( onDoubleTap: _nextQuote, child: Stack( children: [ ColorFiltered( colorFilter: ColorFilter.mode( Colors.black.withOpacity(0.5), BlendMode.darken), child: FadeInImage.assetNetwork( placeholder: 'assets/loading.gif', image: _imageUrl, fit: BoxFit.fitHeight, width: double.maxFinite, height: double.maxFinite, ), ), Padding( padding: const EdgeInsets.all(4.0), child: Center( child: Text( (_quotesList[_currentQuoteIndex].data() as Map)['quote'] .toString() .toUpperCase(), textAlign: TextAlign.center, style: const TextStyle( letterSpacing: 0.8, fontSize: 25.0, color: Colors.white, fontWeight: FontWeight.bold), )), ), Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [ Padding( padding: const EdgeInsets.only(bottom: 50.0), child: Center( child: Text( "- ${(_quotesList[_currentQuoteIndex].data() as Map)['author'].toString().toUpperCase()}", textAlign: TextAlign.right, style: const TextStyle( letterSpacing: 0.8, fontSize: 18.0, color: Colors.white, fontWeight: FontWeight.bold), )), ), ], ), ], ), ), ), ); } }
注意事项
- 如果需要实时同步Firestore后台的名言增删改,可以把
_loadQuotes里的get()换成snapshots()监听,每次数据变动更新本地_quotesList即可 - 提前在
pubspec.yaml中配置好assets/loading.gif的静态资源路径,否则会出现加载报错 - 如果Unsplash随机图接口加载缓慢,可以替换为其他可用的随机图源
内容的提问来源于stack exchange,提问作者damigesh
相关产品推荐
相关产品推荐

