Flutter 异步按钮点击内执行Navigator页面跳转报错如何解决?
问题根因
- 你在
onPressed中发起异步请求时,是用await等待结果返回,在等待的这段时间内,当前页面的Widget可能因为用户操作(比如点击返回键退到上一页)、页面重建等原因被销毁,对应的context已经从Widget树中移除,变成失效状态。 - 异步请求返回后,你直接用已经失效的
context调用Navigator.of(context),就会触发「查找已停用组件的父节点是不安全操作」的异常。你之前用SchedulerBinding包裹逻辑没用,是因为只要用到的是已失效的context,不管什么时候调用都会报错。
解决方案
方案1:判断组件挂载状态(适合StatefulWidget)
StatefulWidget的State类自带mounted属性,可直接判断当前组件是否还挂载在Widget树上,只有挂载状态为真时再执行路由操作:
onPressed: () async { var response = await authBloc.onLogin(_akey, _password); // 先判断组件是否还存在 if (!mounted) return; if (response.isValid) { Navigator.of(context).push(MaterialPageRoute( builder: (context) => Container(), )); } },
方案2:提前获取Navigator实例(适合Stateless/Stateful全场景)
在异步等待开始前,先把当前的Navigator实例存下来,不要等异步结束后再用context获取:
onPressed: () async { // 异步前提前拿到Navigator实例,此时context还是有效状态 final navigator = Navigator.of(context); var response = await authBloc.onLogin(_akey, _password); if (response.isValid) { // 直接用提前拿到的实例执行跳转,不需要再用context navigator.push(MaterialPageRoute( builder: (context) => Container(), )); } },
方案3:使用全局路由Key(适合全局异步场景)
你可以在根MaterialApp中配置全局的NavigatorKey,之后所有路由操作都可以通过这个全局Key执行,完全不依赖页面的context:
- 先定义全局的NavigatorKey
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
- 绑定到MaterialApp
MaterialApp( navigatorKey: navigatorKey, // 其他配置... )
- 异步场景下直接使用key跳转
onPressed: () async { var response = await authBloc.onLogin(_akey, _password); if (response.isValid) { navigatorKey.currentState?.push(MaterialPageRoute( builder: (context) => Container(), )); } },
内容的提问来源于stack exchange,提问作者GPlay97
相关产品推荐
相关产品推荐

