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

Flutter路由改造后出现ProviderNotFoundException问题求助

Flutter路由跳转时ProviderNotFoundException异常排查

原本运行正常的Flutter应用,在添加自定义AppRouter类处理main.dart中的onGenerateRoute路由逻辑后,加载LoginPage时抛出ProviderNotFoundException,错误提示为:无法在BlocListener<LoginCubit, LoginState>组件上方找到正确的Provider<LoginCubit>。

尝试通过创建路由字符串到Map<Widget, Cubit>的映射实现getRoute()函数通用化,但始终抛出异常。相关代码及报错栈如下:

相关代码

AppRouter类代码

class AppRouter {
  static const String homepageRoute = '/';
  static const String loginRoute = '/login';
  static const String prospectsRoute = '/prospects';

  static Map<String, Map<Widget, Cubit>> get _pageMap => {
    loginRoute: { const LoginPage(): LoginCubit(locator.get<LoginRepository>()) },
    homepageRoute: { const HomePage(): HomePageCubit(locator.get<HomePageRepository>()) },
    prospectsRoute: { const ProspectsPage(): ProspectsCubit(locator.get<ProspectsRepository>()) }
  };

  static Route generateRoute(RouteSettings routeSettings){
    return getRoute(routeSettings.name!);
  }

  static Route getRoute(String name){
    final pageMap = _pageMap[name];

    return MaterialPageRoute(
      builder: (context) => BlocProvider(
        create: (create) => pageMap.values.first,
        child: pageMap!.keys.first
      )
    );
  }
}

main.dart核心代码

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // return MultiBlocProvider(
    //   providers: [
    //     // BlocProvider<ProspectsCubit>(create: (context) => ProspectsCubit(locator.get<ProspectsRepository>())),
    //     // BlocProvider<LoginCubit>(create: (context) => LoginCubit(locator.get<LoginRepository>())),
    //     // BlocProvider<HomePageCubit>(create: (context) => HomePageCubit(locator.get<HomePageRepository>()))
    //   ], 
    //   child: 
      return MaterialApp(
        localizationsDelegates: const [ AppLocalizationsDelegate() ],
        onGenerateTitle: (context) => AppLocalizations.of(context).appTitle, // Can't use title property because of i18n
        onGenerateRoute: AppRouter.generateRoute,
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: (AppTheme.darkAccent)),
          useMaterial3: true,
          appBarTheme: const AppBarTheme(
            backgroundColor: AppTheme.dark,
            elevation: 0
          ),
        ),
        initialRoute: Credentials.isAuthenticated ? AppRouter.homepageRoute : AppRouter.loginRoute,
      //)
    );
  }
}

报错栈信息

The relevant error-causing widget was:
  LoginPage
  LoginPage:file:///C:/Users/source/repos/[redacted]/lib/router.dart:21:25

When the exception was thrown, this was the stack:
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 294:3  throw_
packages/provider/src/provider.dart 343:7                                    _inheritedElementOf
packages/provider/src/provider.dart 293:30                                   of
packages/provider/src/provider.dart 649:21                                   ReadContext.read

问题原因及解决办法

核心问题

你在_pageMap中直接实例化LoginCubit等对象,并使用const LoginPage()作为Map的key,这会导致两个关键问题:

  1. const LoginPage()是编译时常量,而LoginCubit是运行时创建的对象,将两者绑定会破坏Cubit的生命周期管理,无法通过BlocProvider正确注入到Widget树中。
  2. 直接在_pageMap中实例化Cubit会导致其在App启动时就被创建,而非路由跳转时,违背了BlocProvider的懒加载原则,同时无法关联到正确的BuildContext。

修正方案

重构_pageMap结构,存储页面和Cubit的构造函数而非实例,在路由跳转时动态创建:

class AppRouter {
  static const String homepageRoute = '/';
  static const String loginRoute = '/login';
  static const String prospectsRoute = '/prospects';

  // 使用Dart记录类型存储路由对应的构造逻辑
  static Map<String, ({Widget Function() pageBuilder, Cubit Function() cubitBuilder})> get _pageMap => {
    loginRoute: (
      pageBuilder: () => const LoginPage(),
      cubitBuilder: () => LoginCubit(locator.get<LoginRepository>())
    ),
    homepageRoute: (
      pageBuilder: () => const HomePage(),
      cubitBuilder: () => HomePageCubit(locator.get<HomePageRepository>())
    ),
    prospectsRoute: (
      pageBuilder: () => const ProspectsPage(),
      cubitBuilder: () => ProspectsCubit(locator.get<ProspectsRepository>())
    ),
  };

  static Route generateRoute(RouteSettings routeSettings){
    return getRoute(routeSettings.name!);
  }

  static Route getRoute(String name){
    final entry = _pageMap[name];
    assert(entry != null, "Unknown route: $name");

    return MaterialPageRoute(
      builder: (context) => BlocProvider(
        create: (context) => entry!.cubitBuilder(),
        child: entry.pageBuilder()
      )
    );
  }
}

额外说明

  • 使用Dart 3.0+的记录类型(Record)让路由映射结构更清晰,也可以用自定义类替代。
  • 通过延迟执行构造函数,确保Cubit和页面在路由跳转时才初始化,保证Cubit生命周期与页面绑定。
  • 添加assert断言可在开发阶段快速定位未知路由问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 23:17:16