Flutter:如何在StreamBuilder的for循环内等待异步函数?
解决StreamBuilder循环内等待异步函数的问题
你的核心问题是StreamBuilder的builder方法是同步执行的,无法直接在内部使用await等待异步函数,同时原代码里直接调用getDataFromSeasons却不等待结果,导致wholeLeagueStatus还没更新就被用来创建LeagueGroupByListModel,最终拿到的是旧值或默认的"Nothing"。
解决方案步骤:
- 重构异步方法,避免依赖全局变量:修改
getDataFromSeasons,让它直接返回计算后的状态值,不再依赖全局变量存储结果,避免多循环迭代时的状态混乱。 - 将循环异步处理转为整体Future:把遍历
publicLeagues并调用异步函数的逻辑封装成一个返回List<LeagueGroupByListModel>的Future。 - 用FutureBuilder嵌套处理异步结果:在StreamBuilder内部,拿到
publicLeagues后,用FutureBuilder等待异步处理完成,再基于处理好的数据构建UI。
修改后的关键代码:
首先修改getDataFromSeasons:
Future<String?> getDataFromSeasons(int roundNumber) async { String round = "round_" + roundNumber.toString(); final seasonModelYear = await _dbServicesFootball.fetchDataFromSeasons(round); if (seasonModelYear == null || seasonModelYear.matches == null) { return null; } final uniqueStatus = <String>{}; final listofStatus = seasonModelYear.matches!.where((element) { if (element.matchStatus != null) { return uniqueStatus.add(element.matchStatus!); } else { return false; } }).toList(); return listofStatus.length == 1 ? listofStatus[0]!.matchStatus : null; }
然后在StreamBuilder内部替换原有的循环逻辑,改用FutureBuilder:
if (publicLeagues.length > 0) { // 封装异步处理逻辑 Future<List<LeagueGroupByListModel>> processLeagues() async { final itemList = <LeagueGroupByListModel>[]; for (final league in publicLeagues) { final status = await getDataFromSeasons(league["startRound"]); itemList.add(LeagueGroupByListModel( name: status ?? "Nothing", listData: league, )); } return itemList; } // 用FutureBuilder等待异步处理完成 return FutureBuilder<List<LeagueGroupByListModel>>( future: processLeagues(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (snapshot.hasData && snapshot.data!.isNotEmpty) { final itemList = snapshot.data!; groupedItems = groupBy(itemList, (item) => item.name); return Padding( padding: const EdgeInsets.only( top: AppPadding.p12, bottom: AppPadding.p8, left: AppPadding.p8, right: AppPadding.p8), child: Column( mainAxisSize: MainAxisSize.min, children: [ Expanded( child: ListView.builder( itemCount: groupedItems!.length, itemBuilder: (BuildContext context, int index) { String status = groupedItems!.keys.elementAt(index); List itemsInData = groupedItems![status]; return Column( children: [ Text( status, style: getSemiBoldStyle( color: ColorManager.leagueTextColor1, ), ), const SizedBox(height: AppSize.s4), Divider( thickness: AppSize.s1_5, color: ColorManager.leagueDividerColor, ), ListView.separated( shrinkWrap: true, physics: const ClampingScrollPhysics(), itemBuilder: (context, idx) { return PublicListWidget( publicData: itemsInData[idx], ); }, separatorBuilder: (context, idx) => const Divider(), itemCount: itemsInData.length, ), ], ); }, ), ), ], ), ); } else { return Center( child: Text( AppStrings.noPubLicLeagueText, style: getBoldStyle(color: ColorManager.white, fontSize: FontSize.s16), ), ); } }, ); } else { return Center( child: Text( AppStrings.noPubLicLeagueText, style: getBoldStyle(color: ColorManager.white, fontSize: FontSize.s16), ), ); }
额外优化建议:
如果各个异步请求之间没有依赖关系,可以用Future.wait并行处理,提升效率:
Future<List<LeagueGroupByListModel>> processLeagues() async { final futures = publicLeagues.map((league) async { final status = await getDataFromSeasons(league["startRound"]); return LeagueGroupByListModel( name: status ?? "Nothing", listData: league, ); }).toList(); return await Future.wait(futures); }
这样所有getDataFromSeasons请求会同时发起,比串行循环更快。
内容的提问来源于stack exchange,提问作者Abhay Varma
相关产品推荐
相关产品推荐

