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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 06:45:36