Flutter嵌套StreamBuilder读取Firestore双集合触发RangeError索引越界
问题原因
- 嵌套StreamBuilder的逻辑存在错位。你先查询到了所有评论数据(snapshot5),但在snapshot5的回调里直接嵌套的用户查询,仅传入了某一条评论对应的reviewerId,导致snapshot6永远只能拿到1条对应用户数据。
- 遍历所有评论的ListView.builder放在了单个用户查询的回调里,当你遍历到第2条评论时,尝试用下标1访问只有1条数据的snapshot6,自然触发下标越界错误。
解决方法
方案1:在ListView的每个item中单独查询对应用户信息
把用户查询的StreamBuilder移到ListView.builder的itemBuilder内部,每条评论单独查询对应的用户信息即可,修改后代码参考:
StreamBuilder<QuerySnapshot>( stream: FirebaseFirestore.instance .collection('carInfo') .doc(snapshot.data!.docs[index].get('CaradvId')) .collection('carReviews') .snapshots(), builder: (context, snapshot5) { if (!snapshot5.hasData) return const CircularProgressIndicator(); return Container( padding: const EdgeInsets.symmetric(horizontal: 5), height: MediaQuery.of(context).size.height * 0.225, child: ListView.builder( shrinkWrap: true, scrollDirection: Axis.horizontal, itemCount: snapshot5.data!.docs.length, itemBuilder: (BuildContext context, int reviewIndex) { var reviewDoc = snapshot5.data!.docs[reviewIndex]; DateTime date = reviewDoc.get('reviewDate').toDate(); String dateString = DateFormat('dd MMM yyyy').format(date); return StreamBuilder<QuerySnapshot>( stream: FirebaseFirestore.instance .collection('users') .where('uid', isEqualTo: reviewDoc.get('reviewerId')) .snapshots(), builder: (context, snapshot6) { if (!snapshot6.hasData) return const CircularProgressIndicator(); var userDoc = snapshot6.data!.docs.first; return ConstrainedBox( child: Card( elevation: 2, child: Container( child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Container( padding: const EdgeInsets.only(left: 12.5, top: 12.5), height: 55, width: 55, child: CircleAvatar( backgroundImage: NetworkImage( userDoc.get('userImage'), ), radius: 40, ), ), Container( padding: const EdgeInsets.only(top: 15), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.only(left: 5), child: RatingBar.builder( initialRating: double.parse(reviewDoc.get('reviewRating')), minRating: 1, direction: Axis.horizontal, allowHalfRating: true, updateOnDrag: false, itemCount: 5, itemSize: 14, itemPadding: const EdgeInsets.symmetric(vertical: 0), itemBuilder: (context, _) => const Icon( Icons.star, color: Colors.amber, ), onRatingUpdate: (rating) { print(rating); }, ), ), const SizedBox(height: 7.5), Row( children: [ Container( padding: const EdgeInsets.only(left: 7.5), child: Text( userDoc.get('userFirstname'), overflow: TextOverflow.ellipsis, maxLines: 1, style: const TextStyle( fontSize: 10, fontWeight: FontWeight.w800, color: Colors.black87, ), ), ), Container( padding: const EdgeInsets.only(left: 2.5), child: Text( dateString, overflow: TextOverflow.ellipsis, maxLines: 1, style: const TextStyle( fontSize: 10, fontWeight: FontWeight.w800, color: Colors.black54, ), ) ) ], ) ], ) ), ], ), Container( padding: const EdgeInsets.only(left: 12.5, top: 12.5), height: 130, width: MediaQuery.of(context).size.width * 0.75, child: Text(reviewDoc.get('reviewContent')), ) ], ), ), ), ); }, ); }, ), ); }, )
方案2:提前合并评论与用户数据
拿到所有评论数据后,一次性查询所有需要的用户数据,合并成一个统一的列表数据再渲染,嵌套层级更少,性能也更好。
内容的提问来源于stack exchange,提问作者Arminmos
相关产品推荐
相关产品推荐

