Flutter异步登录+模态导航报错:Bad state: Future already completed
解决GoRouter中异步跳转登录页导致的Future已完成报错
应用场景
- 设置页:包含触发登录流程的按钮
- 登录页:提供用户输入账号凭证的界面
导航流程
- 在设置页点击登录按钮,通过
showModalBottomSheet(配置useRootNavigator: true)弹出模态框 - 模态框内点击登录按钮,通过
LoginRoute().push(context)跳转到登录页 - 用户在登录页输入凭证后点击登录按钮
- 登录成功时需同时关闭登录页和模态框;登录失败则仅关闭登录页,保留模态框
额外配置
LoginRoute通过全局导航Key确保路由显示在底部导航栏上方:
static final GlobalKey<NavigatorState> $parentNavigatorKey = rootNavigatorKey;
问题描述
登录页的登录操作是异步调用远程API,为了等待登录结果(返回true表示成功),将模态框中跳转登录的方法设为async,并执行:
bool? result = await LoginRoute().push<bool>(context);
但此时触发如下报错:
Unhandled Exception: Bad state: Future already completed
堆栈跟踪:
E/flutter ( 7668): #0 _AsyncCompleter.complete (dart:async/future_impl.dart:84:31) E/flutter ( 7668): #1 ImperativeRouteMatch.complete (package:go_router/src/match.dart:456:15) E/flutter ( 7668): #2 GoRouterDelegate._completeRouteMatch (package:go_router/src/delegate.dart:171:14) E/flutter ( 7668): #3 GoRouterDelegate._handlePopPageWithRouteMatch.<anonymous closure> (package:go_router/src/delegate.dart:151:9)
目前使用WidgetsBinding.instance.addPostFrameCallback((_) {context.pop();})可正常运行,但并非最优方案,需更合理的解决方式。
可行解决方案
方案1:改用then链式调用替代async/await
避免异步上下文持有冲突,通过then处理登录返回结果:
// 模态框内的跳转登录方法 void navigateToLogin(BuildContext context) { LoginRoute().push<bool>(context).then((bool? result) { if (result == true) { // 使用rootNavigator上下文关闭模态框 Navigator.of(context, rootNavigator: true).pop(); } }); }
方案2:分离模态框与登录页的导航上下文
打开模态框时记录其上下文,后续关闭模态框时直接使用该上下文:
// 设置页中打开模态框的代码 void showLoginModal(BuildContext context) async { final modalContext = await showModalBottomSheet( context: context, useRootNavigator: true, builder: (context) => AccountPage(), ); } // AccountPage中处理登录跳转的方法 void onLoginTap(BuildContext modalContext) { LoginRoute().push<bool>(context).then((result) { if (result == true) { Navigator.of(modalContext).pop(); } }); }
方案3:在登录页直接回退到目标路由层级
登录成功时,通过popUntil一次性回退到设置页,自动关闭中间的登录页和模态框:
// 登录页的登录成功逻辑 if (loginSuccess) { // 回退到设置页(需确保设置页路由名称为'SettingsPage') context.popUntil((route) => route.settings.name == 'SettingsPage'); } else { context.pop(); }
内容的提问来源于stack exchange,提问作者zacko
相关产品推荐
相关产品推荐

