Flutter中如何让showDialog等待异步函数执行完再构建组件
Flutter扫码场景异步数据未完成就触发弹窗的空值问题修复
问题现象
- 已完成二维码扫描基础逻辑开发,扫码触发后拉取关联数据时,弹窗组件构建逻辑提前执行,依赖的业务数据为空导致组件报错
- 日志打印顺序可验证时序问题:
showDialog相关逻辑在异步数据获取函数getQRData()执行完毕前就已触发
原问题代码
数据获取函数
void getQRData() async { // Get User Data from ID print('qrcode: $qrcode'); // Take the UserData[Number] to get user short data data = await UserDatabase.getUserShortData( userId: qrcode, phoneNumber: null, ); print('data is : $data'); await Future.forEach( Provider.of<ContactDataProvider>(context, listen: false) .getContactConnection .keys, (key) async { connectedContactData = Provider.of<ContactDataProvider>(context, listen: false) .getContactConnection[key]; print(connectedContactData); if (connectedContactData['status'] == 'connected' || connectedContactData['status'] == 'sent_req') { filteredId.add(connectedContactData['contact_uid']); print('filteredId: ${filteredId}'); } }); }
扫码组件逻辑
Container( width: 250, height: 250, child: ScanView( controller: scanController, scanAreaScale: 0.8, scanLineColor: Colors.red, onCapture: (photoData) { qrcode = photoData; print('qrcode: $qrcode'); getQRData(); print(data); //ShowDialog Widget Code }, ), )
问题根因
Dart中async标记的函数返回Future对象,调用时如果不添加await关键字,程序不会等待异步任务执行完成,会直接同步执行后续逻辑。当前代码在onCapture回调中直接调用getQRData()未加等待,所以调用后立刻执行后续弹窗逻辑,此时data、filteredId等变量还未完成赋值,自然为空。
修复方案
- 将
onCapture回调标记为async,调用getQRData()时添加await关键字,强制等待所有数据拉取、处理逻辑执行完成后,再执行弹窗构建逻辑 - (可选优化)数据等待过程中添加加载态,异常场景添加错误捕获,避免无反馈或崩溃
最小修复代码
onCapture: (photoData) async { // 回调加async支持异步等待 qrcode = photoData; print('qrcode: $qrcode'); await getQRData(); // 加await等待数据拉取完成 print(data); // 此处再编写showDialog逻辑,所有依赖变量已完成赋值 showDialog( context: context, builder: (context) { // 可安全使用data、filteredId等变量构建组件 return const SizedBox(); // 替换为你的业务弹窗组件 } ); },
带加载态与异常捕获的优化版本
onCapture: (photoData) async { qrcode = photoData; try { // 弹出不可关闭的加载提示 showDialog( context: context, barrierDismissible: false, builder: (context) => const Center(child: CircularProgressIndicator()) ); // 等待数据拉取完成 await getQRData(); // 关闭加载框 Navigator.pop(context); // 弹出业务结果弹窗 showDialog( context: context, builder: (context) => const SizedBox() // 替换为你的业务弹窗组件 ); } catch (e) { // 异常场景关闭加载框,弹出错误提示 Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('获取扫码信息失败,请重试')) ); } },
注意:
getQRData函数如果涉及遍历、多接口请求等耗时操作,必须加加载态避免用户误以为页面无响应。
内容的提问来源于stack exchange,提问作者Kim San
相关产品推荐
相关产品推荐

