Flutter:解决StreamBuilder内异步方法执行顺序异常问题
解决StreamBuilder中异步方法顺序执行问题
核心问题
当前代码里_getInfo()和setMarker()都是异步方法,但在StreamBuilder的builder回调中直接同步调用,导致setMarker()在_getInfo()未完成(还没给beetsList元素赋值user)就执行,进而出现user为null的错误。
解决方案一:嵌套FutureBuilder
在StreamBuilder获取到beets集合数据后,用FutureBuilder处理后续异步逻辑,确保先完成用户信息加载,再生成标记:
StreamBuilder<QuerySnapshot>( stream: FirebaseFirestore.instance .collection(CustomCollectionPath.beets) .where('email', isNotEqualTo: currentUser.email) .snapshots(), builder: (context, snapshot) { if (snapshot.hasData) { markers.clear(); _getPosition(snapshot.data!.docs); // 嵌套FutureBuilder保证异步操作顺序 return FutureBuilder<void>( future: _getInfo().then((_) => setMarker()), builder: (context, futureSnapshot) { if (futureSnapshot.connectionState == ConnectionState.done) { return GoogleMap( onMapCreated: _onMapCreated, myLocationEnabled: true, buildingsEnabled: true, myLocationButtonEnabled: false, zoomControlsEnabled: false, markers: markers, mapToolbarEnabled: false, initialCameraPosition: _startPosition, ); } else { return Center(child: CircularProgressIndicator()); } }, ); } else { return Center(child: CircularProgressIndicator()); } }, )
解决方案二:封装异步逻辑并通过setState更新
把加载数据和生成标记的逻辑封装成异步方法,完成后触发UI更新:
首先在State类中添加封装方法:
Future<void> _loadDataAndMarkers(List<QueryDocumentSnapshot> docs) async { markers.clear(); _getPosition(docs); await _getInfo(); // 等待用户信息加载完成 await setMarker(); // 再生成标记 setState(() {}); // 更新UI渲染地图 }
然后修改StreamBuilder:
StreamBuilder<QuerySnapshot>( stream: FirebaseFirestore.instance .collection(CustomCollectionPath.beets) .where('email', isNotEqualTo: currentUser.email) .snapshots(), builder: (context, snapshot) { if (snapshot.hasData) { _loadDataAndMarkers(snapshot.data!.docs); // 根据标记状态返回对应UI return markers.isEmpty ? Center(child: CircularProgressIndicator()) : GoogleMap( onMapCreated: _onMapCreated, myLocationEnabled: true, buildingsEnabled: true, myLocationButtonEnabled: false, zoomControlsEnabled: false, markers: markers, mapToolbarEnabled: false, initialCameraPosition: _startPosition, ); } else { return Center(child: CircularProgressIndicator()); } }, )
额外优化建议
- 处理
firstWhere异常:_getInfo()中使用firstWhere如果找不到匹配元素会报错,建议添加默认值处理:
var matchingBeet = beetsList.firstWhere( (element) => element.email == emailCurrentUser, orElse: () => BeetModel(), // 替换为你的BeetModel默认构造方法 );
- 合并Firestore查询:可以通过Firestore的关联查询或批量操作减少网络请求,避免二次查询userInfo集合。
- 缓存用户信息:若userInfo不会频繁变更,可缓存查询结果,避免每次Stream更新都重复请求。
内容的提问来源于stack exchange,提问作者joisberg
相关产品推荐
相关产品推荐

