使用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é

