You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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());
    }
  },
)

额外优化建议

  1. 处理firstWhere异常:_getInfo()中使用firstWhere如果找不到匹配元素会报错,建议添加默认值处理:
var matchingBeet = beetsList.firstWhere(
  (element) => element.email == emailCurrentUser,
  orElse: () => BeetModel(), // 替换为你的BeetModel默认构造方法
);
  1. 合并Firestore查询:可以通过Firestore的关联查询或批量操作减少网络请求,避免二次查询userInfo集合。
  2. 缓存用户信息:若userInfo不会频繁变更,可缓存查询结果,避免每次Stream更新都重复请求。

内容的提问来源于stack exchange,提问作者joisberg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 18:20:26