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

Flutter登录异步流程弹窗行为异常的代码问题排查

问题描述

我希望在登录流程中展示弹窗以优化用户体验,因为应用在跳转到首页前需要保存部分信息。但弹窗行为存在异常:有时在跳转首页前显示,有时在跳转后显示且无法关闭。相关代码如下:

PrimaryButton(
text: 'Sign In',
press: () async {
if (_formKey.currentState!.validate()) {
final message = await AuthService().login(
email: _emailController.text.trim(),
password: _passwordController.text.trim(),
);
if (message!.contains('Success')) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Signing you in...'),
content: Container(
height: 50.0,
width: 50.0,
color: Colors.red,
child: const Center(
child: CircularProgressIndicator(),
),
),
);
},
);
final currUserID =
FirebaseAuth.instance.currentUser!.uid;
await saveUserModelToHive(currUserID);
await saveSomeInfo();
Navigator.of(context).pop();
if (!mounted) return;
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => const LandingPage(),
),
);
} else {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
duration: const Duration(seconds: 5),
),
);
}
}
},
),
问题原因分析
  • 上下文(Context)混乱:调用showDialog时使用的是当前页面的context,后续的Navigator.pushReplacement会替换当前页面的导航栈。如果saveUserModelToHive和saveSomeInfo执行较慢,页面已被替换,弹窗的上下文会失效,导致弹窗无法关闭;如果这两个操作执行过快,弹窗刚显示就被Navigator.of(context).pop()关闭,用户几乎看不到弹窗。
  • 弹窗关闭逻辑错误:Navigator.of(context).pop()使用的是页面的context,而非弹窗自身的context。当页面跳转后,这个context指向已被销毁的页面,无法正确关闭弹窗。
  • 未同步弹窗生命周期:弹窗的显示和关闭没有与后续异步操作(保存信息、页面跳转)做好同步,导致执行顺序不可控。
修复方案

调整代码逻辑,确保弹窗生命周期与异步操作同步,同时使用弹窗自身的上下文关闭它:

PrimaryButton(
  text: 'Sign In',
  press: () async {
    if (_formKey.currentState!.validate()) {
      final message = await AuthService().login(
        email: _emailController.text.trim(),
        password: _passwordController.text.trim(),
      );
      if (message!.contains('Success')) {
        // 显示弹窗并绑定自身上下文
        await showDialog(
          context: context,
          barrierDismissible: false, // 禁止用户手动关闭弹窗
          builder: (BuildContext dialogContext) {
            // 确保弹窗渲染完成后再执行保存逻辑
            WidgetsBinding.instance.addPostFrameCallback((_) async {
              final currUserID = FirebaseAuth.instance.currentUser!.uid;
              await saveUserModelToHive(currUserID);
              await saveSomeInfo();
              // 使用弹窗自身上下文关闭弹窗
              Navigator.of(dialogContext).pop();
              // 弹窗关闭后再执行页面跳转
              if (!mounted) return;
              Navigator.of(context).pushReplacement(
                MaterialPageRoute(
                  builder: (context) => const LandingPage(),
                ),
              );
            });
            return AlertDialog(
              title: const Text('Signing you in...'),
              content: Container(
                height: 50.0,
                width: 50.0,
                color: Colors.red,
                child: const Center(
                  child: CircularProgressIndicator(),
                ),
              ),
            );
          },
        );
      } else {
        if (!mounted) return;
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text(message),
            duration: const Duration(seconds: 5),
          ),
        );
      }
    }
  },
),
关键优化点
  • 绑定弹窗上下文:在弹窗的builder中使用dialogContext关闭弹窗,确保操作的是弹窗自身的导航栈。
  • 同步异步操作:通过WidgetsBinding.instance.addPostFrameCallback确保弹窗渲染完成后再执行保存逻辑,避免弹窗未显示就执行后续操作。
  • 禁止手动关闭:设置barrierDismissible: false,防止用户在保存过程中手动关闭弹窗,保证流程完整性。
  • 顺序控制:等待弹窗关闭后再执行页面跳转,确保弹窗始终在旧页面显示,不会出现在新页面中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 04:08:27