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

Flutter集成GoRouter后No ScaffoldMessenger错误的解决求助

解决GoRouter重构后BlocListener调用ScaffoldMessenger报错的问题

错误原因

当前BlocListener<GlobalBloc, GlobalState>的上下文位于MaterialApp.router的上层组件树中,而ScaffoldMessenger是由MaterialApp内部提供的,因此上层上下文无法找到对应的ScaffoldMessenger实例,导致报错。

修复方案

方案一:使用全局ScaffoldMessengerKey

通过定义全局的ScaffoldMessengerKey,直接关联到MaterialApp.router,绕过上下文查找的限制:

修改MyApp类:

class MyApp extends StatelessWidget {
  final AuthRepository authRepository;
  // 定义全局ScaffoldMessengerKey
  final GlobalKey<ScaffoldMessengerState> _scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();

  const MyApp({super.key, required this.authRepository});

  @override
  Widget build(BuildContext context) {
    final GoRouter router = GoRouter(
      routes: [
        GoRoute(
          path: '/',
          builder: (context, state) => const MyHomePage(title: 'Flutter Demo Home Page'),
        ),
        GoRoute(
          path: '/settings',
          builder: (context, state) => const SettingsScreen(),
        ),
        GoRoute(
          path: '/profile',
          builder: (context, state) => const ProfileScreen(),
        ),
      ],
    );

    return MultiBlocProvider(
      providers: [
        BlocProvider<GlobalBloc>(
          create: (context) => GlobalBloc(),
        ),
        BlocProvider<AuthBloc>(
          create: (context) => AuthBloc(authRepository: authRepository),
        ),
      ],
      child: Builder(
        builder: (context) {
          return BlocListener<GlobalBloc, GlobalState>(
            listener: (context, state) {
              if (state is GlobalSuccess) {
                _scaffoldMessengerKey.currentState?.hideCurrentSnackBar();
                _scaffoldMessengerKey.currentState?.showSnackBar(
                  SnackBar(
                    content: Text(state.message),
                    backgroundColor: Colors.green,
                  ),
                );
              } else if (state is GlobalError) {
                _scaffoldMessengerKey.currentState?.hideCurrentSnackBar();
                _scaffoldMessengerKey.currentState?.showSnackBar(
                  SnackBar(
                    content: Text(state.message),
                    backgroundColor: Colors.red,
                  ),
                );
              }
            },
            child: BlocBuilder<GlobalBloc, GlobalState>(
              builder: (context, state) {
                bool isLoading = state is GlobalLoading;
                return LoadingOverlay(
                  isLoading: isLoading,
                  child: MaterialApp.router(
                    title: 'Flutter Demo',
                    theme: AppTheme.lightTheme,
                    routerConfig: router,
                    // 将全局key传入MaterialApp
                    scaffoldMessengerKey: _scaffoldMessengerKey,
                  ),
                );
              },
            ),
          );
        },
      ),
    );
  }
}

方案二:将BlocListener嵌入MaterialApp子树

调整组件层级,让BlocListener处于MaterialApp.router的子树中,确保上下文能正确找到ScaffoldMessenger:

修改MyApp类的build方法:

@override
Widget build(BuildContext context) {
  final GoRouter router = GoRouter(
    routes: [
      GoRoute(
        path: '/',
        builder: (context, state) => const MyHomePage(title: 'Flutter Demo Home Page'),
      ),
      GoRoute(
        path: '/settings',
        builder: (context, state) => const SettingsScreen(),
      ),
      GoRoute(
        path: '/profile',
        builder: (context, state) => const ProfileScreen(),
      ),
    ],
  );

  return MultiBlocProvider(
    providers: [
      BlocProvider<GlobalBloc>(
        create: (context) => GlobalBloc(),
      ),
      BlocProvider<AuthBloc>(
        create: (context) => AuthBloc(authRepository: authRepository),
      ),
    ],
    child: BlocBuilder<GlobalBloc, GlobalState>(
      builder: (context, state) {
        bool isLoading = state is GlobalLoading;
        return LoadingOverlay(
          isLoading: isLoading,
          child: MaterialApp.router(
            title: 'Flutter Demo',
            theme: AppTheme.lightTheme,
            routerConfig: router,
            // 通过builder将BlocListener嵌入MaterialApp内部
            builder: (context, child) {
              return BlocListener<GlobalBloc, GlobalState>(
                listener: (context, state) {
                  if (state is GlobalSuccess) {
                    ScaffoldMessenger.of(context).hideCurrentSnackBar();
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(
                        content: Text(state.message),
                        backgroundColor: Colors.green,
                      ),
                    );
                  } else if (state is GlobalError) {
                    ScaffoldMessenger.of(context).hideCurrentSnackBar();
                    ScaffoldMessenger.of(context).showSnackBar(
                      SnackBar(
                        content: Text(state.message),
                        backgroundColor: Colors.red,
                      ),
                    );
                  }
                },
                child: child,
              );
            },
          ),
        );
      },
    ),
  );
}

方案对比

  • 方案一:无需调整组件层级,实现简单,但依赖全局key,需注意空安全处理。
  • 方案二:符合Flutter组件树的上下文查找逻辑,结构更合理,是推荐的标准解决方案。

内容的提问来源于stack exchange,提问作者Dumindu Jayasekara

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 13:27:31