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

Flutter弹窗操作出现Context失效错误,寻求解决方案

问题原因

你在testFunction中使用的context属于第一个AlertDialog的内部组件。当执行Navigator.of(context).pop()关闭该对话框后,这个context对应的Widget已从组件树中被移除(进入deactivated状态),此时再用它操作导航栈(比如关闭加载对话框),Flutter会判定为不安全操作,因为该组件的祖先关系已不稳定。

解决方案

核心是避免使用已失效的context,推荐使用根导航器处理所有对话框的弹出和关闭——根导航器不受当前组件生命周期影响,始终指向App最顶层的导航栈。

修复后的代码

1. 修改testFunction

Future<dynamic> testFunction(BuildContext context) async {
  // 获取根导航器实例,确保所有导航操作都使用它
  final rootNavigator = Navigator.of(context, rootNavigator: true);

  try {
    // 关闭初始的购买对话框
    rootNavigator.pop();

    // 显示加载对话框(禁止点击外部关闭)
    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext dialogCtx) {
        return AlertDialog(
          content: const SizedBox(
            width: 80,
            height: 100,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                CircularProgressIndicator(),
                SizedBox(height: 16),
                Text("Processing purchase..."),
              ],
            ),
          ),
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
          backgroundColor: kBoxColor,
        );
      },
    );

    // 执行Firebase异步请求
    final response = await FirebaseFunctions.instance.httpsCallable('test').call({
      'test': 1,
    });

    // 关闭加载对话框
    rootNavigator.pop();

    // 显示操作完成对话框
    showDialog(
      context: context,
      builder: (BuildContext dialogCtx) {
        return AlertDialog(
          content: const Text("End of function"),
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
          backgroundColor: kBoxColor,
        );
      },
    );

  } on FirebaseFunctionsException catch (_) {
    // 处理Firebase函数异常,先清空所有对话框再跳转错误页
    rootNavigator.popUntil((route) => route.isFirst);
    Navigator.push(context, MaterialPageRoute(builder: (context) => const ErrorScreen()));
  } catch (_) {
    // 处理其他异常
    rootNavigator.popUntil((route) => route.isFirst);
    Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => const ErrorScreen()));
  }
}

2. (可选)优化buildDeckPurchaseDialog

如果你的CustomDialogs工具类内部直接调用showDialog,建议在其中也添加rootNavigator: true,避免类似问题:

static void buildDeckPurchaseDialog(BuildContext context) {
  showDialog(
    context: context,
    rootNavigator: true, // 添加这一行
    builder: (BuildContext dialogCtx) {
      return AlertDialog(
        content: SizedBox(
          width: 80,
          height: 130,
          child: Center(
            MenuAnimatedButton(
              width: 110,
              height: 50,
              function: () => testFunction(context),
            ),
          ),
        ),
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
        backgroundColor: kBoxColor,
      );
    },
  );
}
为什么不需要didChangeDependencies?

你提到的didChangeDependencies是State类的生命周期方法,用于组件依赖的InheritedWidget变化时更新状态,或在dispose中需要访问祖先组件时提前保存引用。但你的问题本质是使用了已被移除组件的context,和组件依赖关系无关,因此不需要用这个方法解决。

内容的提问来源于stack exchange,提问作者Sergio De Crescenzo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 03:50:26