Flutter用StreamBuilder替代FutureBuilder突破Firestore whereIn10条限制
实现方案
核心逻辑分为两部分:一是拆分查询参数解决Firestore whereIn 最多10个参数的限制,二是改造为Stream监听实现数据自动更新。
1. 改造Bloc层数据逻辑
final FirebaseFirestore firestore = FirebaseFirestore.instance; // 返回用户点赞内容的Stream Stream<List<QueryDocumentSnapshot>> getLovedContentsStream() async* { // 获取当前登录用户uid SharedPreferences sp = await SharedPreferences.getInstance(); String _uid = sp.getString('uid') ?? ''; if(_uid.isEmpty) { yield []; return; } // 监听用户文档变化,点赞/取消点赞会自动触发重查 await for (DocumentSnapshot userSnap in firestore.collection('users').doc(_uid).snapshots()) { List lovedTimestamps = userSnap.get('loved items') ?? []; if(lovedTimestamps.isEmpty) { yield []; continue; } // 拆分点赞列表为每10个一组,突破whereIn参数限制 List<List> chunks = []; for (int i = 0; i < lovedTimestamps.length; i += 10) { int end = (i + 10 < lovedTimestamps.length) ? i + 10 : lovedTimestamps.length; chunks.add(lovedTimestamps.sublist(i, end)); } // 分批发起查询合并结果 List<Future<QuerySnapshot>> queryFutures = chunks.map((chunk) { return firestore.collection('contents').where('timestamp', whereIn: chunk).get(); }).toList(); List<QuerySnapshot> allQueryResult = await Future.wait(queryFutures); List<QueryDocumentSnapshot> filteredData = []; for (var snap in allQueryResult) { filteredData.addAll(snap.docs); } // 按用户点赞列表顺序排序,避免展示顺序混乱 filteredData.sort((a, b) { int indexA = lovedTimestamps.indexOf(a.get('timestamp')); int indexB = lovedTimestamps.indexOf(b.get('timestamp')); return indexA.compareTo(indexB); }); yield filteredData; notifyListeners(); } }
2. 改造UI层渲染逻辑
将原有FutureBuilder替换为StreamBuilder即可,原有_buildList方法无需任何修改:
body: sb.guestUser == true ? EmptyPage( icon: FontAwesomeIcons.heart, title: 'No wallpapers found.\n Sign in to access this feature', ) : StreamBuilder<List<QueryDocumentSnapshot>>( stream: context.watch<BookmarkBloc>().getLovedContentsStream(), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasData) { if (snapshot.data!.isEmpty) return EmptyPage( icon: FontAwesomeIcons.heart, title: 'No wallpapers found', ); return _buildList(snapshot); } else if (snapshot.hasError) { return Center( child: Text(snapshot.error.toString()), ); } return Center( child: CupertinoActivityIndicator(), ); }, ),
该实现同时支持拉取超过10条的点赞内容,且用户新增/取消点赞后页面会自动同步更新,无需手动触发刷新。
内容的提问来源于stack exchange,提问作者ARUN BALAJI
相关产品推荐
相关产品推荐

