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

使用Dio发送HTTP请求时遇State上下文失效问题求助

问题描述

使用Dio发送HTTP请求时遇到错误,相关代码如下:

void register() async {
    // 显示加载弹窗
    showDialog(
      context: context,
      builder: (context) => const Center(
        child: CircularProgressIndicator(),
      ),
    );

    // 尝试创建用户
    try {
      UserCredential? userCredential = await FirebaseAuth.instance
          .createUserWithEmailAndPassword(
              email: _emailController.text, password: _passwordController.text);

      Navigator.pop(context);

      // 创建用户文档并发送至API
      createUserData(userCredential.user!.uid);

      // 关闭加载弹窗
    } on FirebaseException catch (e) {
      // 关闭加载弹窗
      //Navigator.pop(context);

      // 向用户展示错误信息
      displayNotification(context, e.code);
    }
  }

  void createUserData(String uid) async {
    try {
      var data = {
        "userId": uid,
        "clientName": _firstNameController.text.toString(),
        "email": _emailController.text.toString(),
      };

      Response response =
          await Dio().post(createAccountEndpoint, data: jsonEncode(data));

      if (response.statusCode == 200) {
        // 展示提示信息
        displayNotification(context, "Your account was created successfully!");
        Navigator.push(
          context,
          MaterialPageRoute(builder: (context) => const LoginOrRegister()),
        );
      } else {
        displayNotification(context, "Error!");
      }
    } on DioException catch (e) {
      print("Create Account ERROR ->  ${e.message}");
    }
  }

执行createUserData(userCredential.user!.uid);时触发错误:

This widget has been unmounted, so the State no longer has a context (and should be considered defunct. Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active

已尝试注释该行代码,程序可正常运行但无法发送请求;调整Navigator.pop()的调用位置,问题仍未解决,寻求帮助。


解决方案

这个错误的核心是异步操作完成时,当前页面的State已经被卸载,导致无法使用context执行UI操作。createUserData是异步函数,当它执行到弹窗提示或页面导航时,当前页面可能已经被销毁,此时context失效。

1. 在异步操作中检查State的mounted状态

所有需要使用context的UI操作前,先判断当前State是否还处于挂载状态。修改后的createUserData函数:

void createUserData(String uid) async {
  try {
    var data = {
      "userId": uid,
      "clientName": _firstNameController.text.toString(),
      "email": _emailController.text.toString(),
    };

    Response response = await Dio().post(createAccountEndpoint, data: jsonEncode(data));

    // 先确认页面还未被卸载
    if (!mounted) return;

    if (response.statusCode == 200) {
      displayNotification(context, "Your account was created successfully!");
      Navigator.push(
        context,
        MaterialPageRoute(builder: (context) => const LoginOrRegister()),
      );
    } else {
      displayNotification(context, "Error!");
    }
  } on DioException catch (e) {
    print("Create Account ERROR ->  ${e.message}");
    // 错误提示也需检查mounted状态
    if (mounted) {
      displayNotification(context, "Failed to create account: ${e.message ?? 'Unknown error'}");
    }
  }
}

2. 修复加载弹窗的关闭逻辑

原代码中异常分支的弹窗关闭代码被注释,会导致加载弹窗一直停留在界面,后续操作更容易引发context问题。修改register函数的异常分支:

on FirebaseException catch (e) {
  // 必须关闭加载弹窗
  Navigator.pop(context);
  // 检查mounted再显示错误提示
  if (mounted) {
    displayNotification(context, e.code);
  }
}

3. 可选优化:使用pushReplacement替代push

如果createUserData执行完成后不需要返回原页面,用pushReplacement替代push,避免返回时出现状态异常:

Navigator.pushReplacement(
  context,
  MaterialPageRoute(builder: (context) => const LoginOrRegister()),
);

核心逻辑:Flutter的StatefulWidget被卸载后,mounted属性会变为false,所有涉及context的UI操作必须在mounted为true时执行。异步操作(比如Dio请求)耗时不确定,必须在操作完成后先做挂载检查。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 02:33:33