Flutter:GoRouter结合Bloc实现闪屏页跳转登录页遇卡顿问题求助
解决Flutter中GoRouter闪屏页无法跳转问题
核心问题分析
- 混用GoRouter与Navigator两种路由跳转方式,导致路由栈混乱,无法正确触发页面跳转。
- GoRouter的
redirect逻辑位置错误,干扰了闪屏页的状态校验流程。 - 闪屏页中
Future.delayed未做重复执行防护,且未判断Widget挂载状态,可能导致无效跳转或异常。
具体修复步骤
1. 统一路由跳转方式,移除Navigator调用
闪屏页的BlocConsumer listener中同时存在GoRouter和Navigator跳转,必须只保留GoRouter的跳转逻辑,避免路由栈冲突:
listener: (context, state) { if (kDebugMode) { print('Listener: $state'); } Future.delayed(const Duration(seconds: 3), () { if (!mounted) return; // 避免Widget销毁后执行跳转 if (state.authStatus == AuthStatus.unAuthenticated) { GoRouter.of(context).go('/login'); // 仅保留GoRouter跳转 } else if (state.authStatus == AuthStatus.authenticated) { GoRouter.of(context).go('/homePage'); } }); },
2. 调整GoRouter的redirect与状态监听逻辑
将redirect逻辑改为全局配置,并添加refreshListenable监听AuthenticationBloc状态变化,确保路由与认证状态同步,同时允许闪屏页正常显示:
GoRouter _router(AuthenticationBloc bloc) { return GoRouter( routes: <GoRoute>[ GoRoute( path: '/', builder: (context, state) => const SplashScreen(), ), GoRoute(path: '/login', builder: (context, state) => LoginScreen()), GoRoute(path: '/signUp', builder: (context, state) => SignUpScreen()), GoRoute(path: '/homePage', builder: (context, state) => HomePage()), ], redirect: (BuildContext context, GoRouterState state) { final isLoggedIn = bloc.state.authStatus == AuthStatus.authenticated; final isSplash = state.location == '/'; final isLoggingIn = state.location == '/login'; // 已登录且不在首页/闪屏页时,跳转至首页 if (isLoggedIn && state.location != '/homePage' && !isSplash) { return '/homePage'; } // 未登录且不在登录页/闪屏页时,跳转至登录页 if (!isLoggedIn && !isLoggingIn && !isSplash) { return '/login'; } // 闪屏页正常展示,不触发跳转 return null; }, // 监听Bloc状态变化,自动更新路由 refreshListenable: bloc, ); }
3. 优化闪屏页跳转逻辑,避免重复执行
添加跳转标记_hasNavigated,确保跳转仅执行一次;同时在didChangeDependencies中初始化处理当前认证状态,覆盖状态未变化的场景:
class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderStateMixin { bool _hasNavigated = false; // 标记是否已完成跳转 @override void didChangeDependencies() { super.didChangeDependencies(); // 初始化时获取当前认证状态,触发跳转逻辑 final currentState = context.read<AuthenticationBloc>().state; _handleNavigation(currentState); } void _handleNavigation(AuthenticationState state) { if (_hasNavigated) return; // 避免重复跳转 Future.delayed(const Duration(seconds: 3), () { if (!mounted) return; _hasNavigated = true; if (state.authStatus == AuthStatus.unAuthenticated) { GoRouter.of(context).go('/login'); } else if (state.authStatus == AuthStatus.authenticated) { GoRouter.of(context).go('/homePage'); } }); } @override Widget build(BuildContext context) { return BlocConsumer<AuthenticationBloc, AuthenticationState>( listener: (context, state) { if (kDebugMode) { print('Listener: $state'); } _handleNavigation(state); }, builder: (context, state) { if (kDebugMode) { print('object: $state'); } // 保持原有UI代码不变 return Scaffold( body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Text( "Welcome to Musajjal", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18), ), const SizedBox(height: 20), Image.asset( 'assets/musajjalBlue.png', width: 300, height: 300, ), const SizedBox(height: 20), const Text( "Hifz ul Quran Records", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18), ), const SizedBox(height: 20), const CircularProgressIndicator(color: Colors.blueGrey), ], ), ), ); }, ); } }
关键注意事项
- 禁止混用GoRouter与Navigator跳转,否则会导致路由栈混乱,无法正确触发页面切换。
- 使用
refreshListenable绑定Bloc,确保认证状态变化时自动同步路由。 - 跳转前必须判断
mounted状态,避免Widget销毁后调用context引发异常。
内容的提问来源于stack exchange,提问作者sulli110
相关产品推荐
相关产品推荐

