Flutter中Firestore读取量异常偏高原因及优化方案问询
问题描述
首页通过3个ListView.builder加载Firestore数据,代码实现如下:
初始化三个Future的方法:
getFuture() async { setState(() { Future1 = FirebaseFirestore.instance.collection("Posts").orderBy(sortBy, descending: descending).limit(20).get(); Future2 = FirebaseFirestore.instance.collection("Posts").orderBy("source", descending: descending).limit(10).get(); Future3 = FirebaseFirestore.instance.collection("Posts").orderBy("date_sort", descending: descending).limit(10).get(); }); }
仅对Future1实现懒加载:
getDocumentsNext(String sortBy, bool descending) async { var lastVisible = collectionState!.docs[collectionState!.docs.length-1]; print('listDocument legnth: ${collectionState!.size} last: $lastVisible'); collection = FirebaseFirestore.instance.collection('Posts').orderBy(sortBy, descending: descending).startAfterDocument(lastVisible).limit(25).get(); fetchDocuments(collection!); } fetchDocuments(Future collection){ collection.then((value) { collectionState = value; value.docs.forEach((element) { setState(() { listDocument.add((element.data())); }); }); }); }
实际测试发现:仅Future1滚动加载(5次滚动共加载125条),但Firebase控制台显示读取量超1000次;滚动10次读取量达4000-5000次,远超过实际加载的文档数量(数据集共3000条,实际加载不足500条)。
原因分析
- setState触发重复请求:每次调用
setState(比如懒加载添加数据时),页面会触发重build。如果Future2、Future3的初始化逻辑会在build中重复执行(比如getFuture被频繁调用),每次build都会重新发起这两个集合的10条数据请求,多次滚动后重复请求的累积会导致读取量暴增。 - 循环调用setState引发频繁重渲染:在
fetchDocuments中,遍历每个文档都单独调用一次setState,这会导致组件多次重build,每次重build又可能触发其他Future的重复请求,进一步放大读取量。 - Future未缓存:
Future1、Future2、Future3没有被正确缓存,每次build都会创建新的Future实例,触发新的Firestore读取请求,而非复用已有的请求结果。
解决方案
缓存Future,避免重复初始化
- 将
Future2、Future3的初始化移至initState,仅在排序条件变化时才重新调用getFuture更新,而非每次setState都重新赋值。 - 使用
FutureBuilder时,确保传入的Future是缓存的成员变量,而非在build方法中直接创建。
- 将
批量更新状态
修改fetchDocuments,先批量收集新数据,再一次性调用setState,减少重渲染次数:fetchDocuments(Future collection){ collection.then((value) { collectionState = value; // 批量转换数据 final newDocs = value.docs.map((doc) => doc.data()).toList(); setState(() { // 一次性添加所有新数据 listDocument.addAll(newDocs); }); }); }防止列表重建触发重复请求
如果三个列表在同一个滚动页面或Tab中,给每个列表所在的StatefulWidget添加AutomaticKeepAliveClientMixin,重写wantKeepAlive返回true,避免列表被销毁重建时重复发起请求。避免在build方法中直接发起请求
确保所有Firestore的get()请求只在初始化、排序条件变更或懒加载时触发,不要在build方法中直接调用请求逻辑,防止build频繁执行导致重复请求。
内容的提问来源于stack exchange,提问作者icantcode
相关产品推荐
相关产品推荐

