Flutter使用Firebase查询结合Model类时map内print不执行问题
Flutter Firestore查询Stream回调不执行问题
问题背景
在Flutter项目中对接Firebase Firestore实现数据查询时,做了如下前置操作:
- 定义业务数据类
ProductModel - 在Firestore的
ProductModel集合下新增2条测试文档数据 - 编写按钮点击触发的
getMessagesTestTest()方法实现数据查询逻辑
问题现象
点击按钮触发查询函数执行后,snapshots().map()回调循环内的print("start in loop");、print('doc.id == ${doc.id}');两条打印语句始终没有输出,notesFromFirestore列表一直为空,判断为代码逻辑实现错误导致。
问题相关代码
初始查询函数实现
void getMessagesTestTest() async{ final aa = await _firestore.collection('ProductModel').snapshots().map((notes){ notesFromFirestore.clear(); for(final DocumentSnapshot<Map<String,dynamic>> doc in notes.docs){ print("start in loop"); print('doc.id == ${doc.id}'); notesFromFirestore.add(ProductModel.fromDocumentSnapshot(doc:doc)); } return notesFromFirestore;}); print( 'List Size = ${notesFromFirestore.length}'); var count = 0; for (final ProductModel notesFromFirestoreA in notesFromFirestore) { count++; print('Loop Counter == ${count}'); print('Id == ${notesFromFirestoreA.id}'); print('Name == ${notesFromFirestoreA.name}'); print('Price == ${notesFromFirestoreA.price}'); print('Brand == ${notesFromFirestoreA.brand}'); print('image == ${notesFromFirestoreA.image}'); } }
按钮点击触发逻辑
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Record'), leading: null, actions: <Widget>[ IconButton( icon: const Icon(Icons.add), onPressed: (){ Navigator.pushNamed(context, creationCategory.id); }, ), IconButton( icon: const Icon(Icons.settings), onPressed: () async { getMessagesTestTest(); }, ), ], ), body: SafeArea( child: Container( child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Text('Trahs Collection', style: const TextStyle( color: Colors.black38, fontWeight: FontWeight.bold, fontSize: 40), ), ItemStream(), ], ), ), ), ); }
ProductModel数据类定义
class ProductModel { static const ID = "id"; static const IMAGE = "image"; static const NAME = "name"; static const BRAND = "brand"; static const PRICE = "price"; String? id; String? image; String? name; String? brand; int? price; ProductModel( {required this.id, required this.image, required this.name, required this.brand, required this.price}); factory ProductModel.fromFire(QueryDocumentSnapshot snapshot) { return ProductModel.fromMap(snapshot as Map<String, dynamic>); } factory ProductModel.fromDocumentSnapshot({required DocumentSnapshot<Map<String,dynamic>> doc}){ return ProductModel( id: doc.data()!["id"], image: doc.data()!["image"], name: doc.data()!["name"], brand: doc.data()!["brand"], price: doc.data()!["price"], ); } Map<String, dynamic> toJson() => { 'id': id, 'image': image, 'name': name, 'brand': brand, 'price': price, }; ProductModel.fromMap(Map<String, dynamic> data) { id = data[ID]; image = data[IMAGE]; name = data[NAME]; brand = data[BRAND]; price = data[PRICE]; } }
问题根因与修复
根因说明
snapshots()方法返回值为Stream类型,Dart中的Stream是懒执行对象:仅对Stream做map转换操作但不调用listen()注册监听的话,Stream不会实际启动数据拉取流程,因此map回调内的逻辑永远不会触发。
修复后代码
2022-06-21调整代码,将函数返回值改为Future<void>,为map转换后的Stream添加listen监听后功能正常,代码如下:
Future<void> getMessagesTestTest() async{ var aa = await _firestore.collection('ProductModel').snapshots().map((notes){ notesFromFirestore.clear(); for(final DocumentSnapshot<Map<String,dynamic>> doc in notes.docs){ log("start in loop"); log('doc.id == ${doc.id}'); notesFromFirestore.add(ProductModel.fromDocumentSnapshot(doc:doc)); } return notesFromFirestore;}); aa.listen( (event) => print("Data Retrieved"), ); print( 'List Size = ${notesFromFirestore.length}'); var count = 0; for (final ProductModel notesFromFirestoreA in notesFromFirestore) { count++; print('Loop Counter == ${count}'); print('Id == ${notesFromFirestoreA.id}'); print('Name == ${notesFromFirestoreA.name}'); print('Price == ${notesFromFirestoreA.price}'); print('Brand == ${notesFromFirestoreA.brand}'); print('image == ${notesFromFirestoreA.image}'); } }
内容的提问来源于stack exchange,提问作者Frederic Chang
相关产品推荐
相关产品推荐

