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

Flutter中如何等待函数执行完成后再显示对应组件

问题背景

开发二维码扫描添加联系人功能,已完成二维码生成、扫码相机模块开发,预期实现用户扫描他人二维码后弹出Dialog展示被扫描用户信息。运行时抛出'Null' is not type of 'String'报错,已初步定位为数据库拉取用户信息存在耗时,data字段仍为null时相关组件已经开始构建导致。

问题根因
  • 异步流程缺失加载状态管理:扫码成功后立即触发UI构建弹窗,但异步方法getQRData()未执行完成,data仍为初始null值
  • 空值场景无兼容处理:构建弹窗内容时直接读取data['nickname']等字段,未判断data是否已赋值,null值传入要求String类型的组件参数时直接触发类型错误
  • 数据返回后未触发界面刷新:原逻辑中getQRData()拿到数据库返回结果后,未调用setState通知框架更新UI,数据加载完成后弹窗内容也不会自动刷新
修复步骤

1. 新增状态标记

在对应State类中初始化状态变量,区分加载中、加载完成的不同场景:

// 存储拉取到的用户信息,初始为null
Map<String, dynamic>? data;
// 数据加载状态标记
bool isLoading = false;

2. 改造异步数据拉取方法

在数据拉取前后更新状态,补充异常捕获,避免加载状态卡死,同时给可能为null的字段加空安全处理:

void getQRData() async {
  // 进入加载状态
  setState(() {
    isLoading = true;
  });

  try {
    await UserDatabase.getContactData(
      contactId: barcode!.code.toString(),
      data: data,
    );

    final userData = await UserDatabase.getUserShortData(
      userId: barcode!.code.toString(),
      // 加空安全,避免data为null时读取mobile_no报错
      phoneNumber: data?['mobile_no'],
    );

    // 数据拉取完成,更新数据、关闭加载态,触发UI刷新
    setState(() {
      data = userData;
      isLoading = false;
    });
    print(data);
  } catch (e) {
    // 请求异常时也要关闭加载态,避免一直转圈
    setState(() {
      isLoading = false;
    });
    // 可在此处补充错误提示逻辑,比如toast提示"获取对方信息失败,请重试"
    print('拉取联系人信息异常: $e');
  }
}

3. 改造Dialog构建逻辑

根据加载状态、数据是否存在展示对应内容,所有读取map字段的位置加空值兜底,避免null传入String类型参数:

Widget build(BuildContext context){
  /// 其他原有代码
  if (barcode != null)
    Dialog(
      shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(12.0)),
      child: Container(
        height: 160,
        padding: EdgeInsets.only(top: 10, right: 10, left: 10),
        // 加载中或数据未就绪时展示加载指示器
        child: isLoading || data == null
            ? const Center(child: CircularProgressIndicator())
            // 数据就绪后展示实际联系人信息
            : Column(
                mainAxisSize: MainAxisSize.min,
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  // 扫码用户头像
                  BuildProfilePicture(
                    radius: 20,
                    // 空值兜底,字段不存在时传空字符串
                    nickname: data!['nickname'] ?? '',
                    profileLink: '',
                  ),

                  // 扫码用户昵称
                  Text(
                    // 空值兜底,避免昵称字段为null时报错
                    data!['nickname'] ?? '未知用户',
                    style: primaryColor600Style.copyWith(fontSize: 18),
                    textAlign: TextAlign.center,
                  ),

                  // 添加提示文案
                  Padding(
                    padding: EdgeInsets.symmetric(horizontal: 13),
                    child: Text(
                      'Add this person to your contact list',
                      textAlign: TextAlign.center,
                      style: primaryColor400Style.copyWith(
                        fontSize: 12,
                        color: Colors.black,
                      ),
                    ),
                  ),

                  // 添加联系人按钮
                  Flexible(
                    child: GestureDetector(
                      onTap: () {
                        controller?.resumeCamera();
                        // 点击后重置状态,避免下次扫码残留旧数据
                        setState(() {
                          barcode = null;
                          data = null;
                        });
                        // 在此处补充实际保存联系人到本地的逻辑
                      },
                      child: Container(
                        height: 30,
                        decoration: BoxDecoration(
                          color: accentColor,
                          borderRadius: BorderRadius.circular(15),
                        ),
                        child: Center(
                          child: Text(
                            'Add to contact',
                            style: TextStyle(
                              color: Colors.white,
                            ),
                          ),
                        ),
                      ),
                    ),
                  )
                ],
              ),
      ),
    ),
}
优化建议
  • 扫码回调处增加重复触发拦截,避免用户在弹窗弹出前重复扫码,导致多次发起数据库请求
  • 所有从接口/数据库返回的map中读取的字段,都建议加?? 兜底值的空值处理,避免后端/数据库返回null时触发类型错误
  • 弹窗关闭场景(比如点击蒙层关闭)也要记得重置barcode、data、isLoading状态,避免状态残留

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 15:57:15