Flutter Bloc:RepositoryProvider与.value区别及代码报错原因解析
已知Flutter Bloc中RepositoryProvider与RepositoryProvider.value的区别:前者自动创建Repository实例,后者接收已创建的实例。但以下两段代码中,代码1运行正常,代码2却抛出如下错误:
RepositoryProvider.of() called with a context that does not contain a repository of type AuthRepository.
No ancestor could be found starting from the context that was passed to RepositoryProvider.of
(). This can happen if the context you used comes from a widget above the RepositoryProvider.
The context used was: HomeScreen(dirty)
代码1:运行成功
class MyApp { void main() { // 1) 让RepositoryProvider创建AuthRepository实例 runApp(RepositoryProvider( create: (context) => AuthRepository(), // 注:原代码拼写错误为crate,应为create child: BlocProvider( create: (context) => AuthCubit(authRepository: RepositoryProvider.of<AuthRepository>(context)), child: const MaterialApp( // 2) 展示将访问AuthRepository实例的HomeScreen home: HomeScreen() ) ) )); } } class HomeScreen extends StatelessWidget { const HomeScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final authCubit = BlocProvider.of<AuthCubit>(context); // 3) 此处调用成功 final authRepo = RepositoryProvider.of<AuthRepository>(context); return Scaffold( body: BlocBuilder<AuthCubit, AuthState>( builder: (context, state) { return Text(state.toString()); }, ), ); } }
代码2:抛出错误
class MyApp { void main() { // 1) 创建AuthRepository实例 final authRepo = AuthRepository(); // 2) 将实例传入RepositoryProvider.value runApp(RepositoryProvider.value( value: (context) => authRepo, // 这里是错误根源 child: BlocProvider( create: (context) => AuthCubit(authRepository: authRepo), child: const MaterialApp( // 3) 展示将访问AuthRepository实例的HomeScreen home: HomeScreen() ) ) )); } } class HomeScreen extends StatelessWidget { const HomeScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final authCubit = BlocProvider.of<AuthCubit>(context); // 4) 此处调用失败 final authRepo = RepositoryProvider.of<AuthRepository>(context); return Scaffold( body: BlocBuilder<AuthCubit, AuthState>( builder: (context, state) { return Text(state.authenticationStatus.toString()); }, ), ); } }
报错原因分析
代码2的核心错误是**RepositoryProvider.value的参数传递错误**:
RepositoryProvider.value的value参数要求直接传入已创建好的Repository实例,而不是一个返回实例的函数。- 你在代码中写了
value: (context) => authRepo,这相当于把一个Function(BuildContext) -> AuthRepository类型的函数当成了要提供的实例,而非真正的AuthRepository对象。
当HomeScreen中调用RepositoryProvider.of<AuthRepository>(context)时,框架会在上下文的祖先组件中查找类型为AuthRepository的Provider,但实际存在的是一个函数类型的Provider,完全不匹配,因此抛出找不到对应Repository的错误。
修正方法
只需将RepositoryProvider.value的value参数改为直接传入已创建的实例即可:
runApp(RepositoryProvider.value( value: authRepo, // 直接传递实例,而非函数 child: BlocProvider( create: (context) => AuthCubit(authRepository: authRepo), child: const MaterialApp( home: HomeScreen() ) ) ));
内容的提问来源于stack exchange,提问作者michielve

