无法在此测试小部件上方找到正确的提供程序
======== 手势捕获异常======================================== ========================= 处理手势时抛出以下 ProviderNotFoundException: 错误:在此测试小部件之上找不到正确的提供程序
发生这种情况是因为您使用了不包含提供程序的 BuildContext
由您选择。有一些常见的场景:
您在
main.dart
中添加了一个新的提供程序并执行了热重载。 要修复此问题,请执行热重启。您尝试读取的提供商位于不同的路线。
提供者是有“范围的”。因此,如果您在路线中插入提供者,那么 其他路由将无法访问该提供商。
您使用的
BuildContext
是您尝试读取的提供程序的祖先。确保测试位于您的 MultiProvider/Provider 下。 当您创建提供程序并尝试立即读取它时,通常会发生这种情况。
例如,而不是:
小部件构建(BuildContext context){ 返回提供者<示例>( 创建:(_) =>例子(), // 会抛出 ProviderNotFoundError,因为 `context` 是关联的 // 到作为 `Provider
` 父级的小部件 子:文本(context.watch<示例>()), ), } 考虑使用
builder
,如下所示:小部件构建(BuildContext context){ 返回提供者<示例>( 创建:(_) =>例子(), // 我们使用 `builder` 来获取一个可以访问提供者的新的 `BuildContext` 构建器:(上下文){ // 不再抛出异常 返回文本(context.watch<示例>()), } ), }
如果这些解决方案都不起作用,请考虑在 StackOverflow 上寻求帮助: https://stackoverflow.com/questions/tagged/flutter
我正在构建一个小部件“测试”来搜索用户通过他们的用户名。这是使用 Bloc 进行测试的小部件。
class Test extends StatelessWidget {
const Test({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => DonorsCubit(),
child: BlocListener<DonorsCubit, DonorsState>(
listener: (context, state) {
print(state);
},
child: Scaffold(
appBar: AppBar(),
body: IconButton(
onPressed: () {
context.read<DonorsCubit>().searchDonors(searchKey: "masum");
},
icon: BlocBuilder<DonorsCubit, DonorsState>(
builder: (context, state) {
if (state is DonorsInitialState) return const Icon(Icons.add);
if (state is DonorsLoadedState) return const Icon(Icons.done);
if (state is DonorsLoadingState) return const Icon(Icons.circle);
return const SizedBox();
},
),
),
),
),
);
}
}
我使用这个肘节来管理状态。
class DonorsCubit extends Cubit<DonorsState> {
List<MyUser> users = <MyUser>[];
final FirebaseDBRepo _firebaseDBRepo = FirebaseDBRepo();
late StreamSubscription _streamSubscription;
DonorsCubit() : super(DonorsInitialState()) {
_streamSubscription =
_firebaseDBRepo.usersStream().listen((List<MyUser> users) {
this.users = users;
});
}
void searchDonors({required String? searchKey}) {
emit(DonorsLoadingState());
List<MyUser> searchedUser = <MyUser>[];
searchedUser.clear();
if (searchKey == null) {
emit(DonorsLoadedState(users: users));
} else {
for (MyUser user in users) {
if (user.username!.toLowerCase().contains(searchKey.toLowerCase())) {
searchedUser.add(user);
}
}
emit(DonorsLoadedState(users: searchedUser));
}
}
@override
Future<void> close() {
_streamSubscription.cancel();
return super.close();
}
}
abstract class DonorsState extends Equatable {
const DonorsState();
}
class DonorsLoadingState extends DonorsState {
@override
List<Object> get props => [];
}
class DonorsInitialState extends DonorsState {
@override
List<Object> get props => [];
}
class DonorsLoadedState extends DonorsState {
final List<MyUser> users;
const DonorsLoadedState({required this.users});
@override
List<Object?> get props => [users];
}
======== Exception caught by gesture ===============================================================
The following ProviderNotFoundException was thrown while handling a gesture:
Error: Could not find the correct Provider above this Test Widget
This happens because you used a BuildContext
that does not include the provider
of your choice. There are a few common scenarios:
You added a new provider in your
main.dart
and performed a hot-reload.
To fix, perform a hot-restart.The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route, then
other routes will not be able to access that provider.You used a
BuildContext
that is an ancestor of the provider you are trying to read.Make sure that Test is under your MultiProvider/Provider.
This usually happens when you are creating a provider and trying to read it immediately.For example, instead of:
Widget build(BuildContext context) { return Provider<Example>( create: (_) => Example(), // Will throw a ProviderNotFoundError, because `context` is associated // to the widget that is the parent of `Provider<Example>` child: Text(context.watch<Example>()), ), }
consider using
builder
like so:Widget build(BuildContext context) { return Provider<Example>( create: (_) => Example(), // we use `builder` to obtain a new `BuildContext` that has access to the provider builder: (context) { // No longer throws return Text(context.watch<Example>()), } ), }
If none of these solutions work, consider asking for help on StackOverflow:
https://stackoverflow.com/questions/tagged/flutter
I am building an Widget "Test" to search users by their username. This is the widget Test with Bloc.
class Test extends StatelessWidget {
const Test({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => DonorsCubit(),
child: BlocListener<DonorsCubit, DonorsState>(
listener: (context, state) {
print(state);
},
child: Scaffold(
appBar: AppBar(),
body: IconButton(
onPressed: () {
context.read<DonorsCubit>().searchDonors(searchKey: "masum");
},
icon: BlocBuilder<DonorsCubit, DonorsState>(
builder: (context, state) {
if (state is DonorsInitialState) return const Icon(Icons.add);
if (state is DonorsLoadedState) return const Icon(Icons.done);
if (state is DonorsLoadingState) return const Icon(Icons.circle);
return const SizedBox();
},
),
),
),
),
);
}
}
I used this cubit to manage states.
class DonorsCubit extends Cubit<DonorsState> {
List<MyUser> users = <MyUser>[];
final FirebaseDBRepo _firebaseDBRepo = FirebaseDBRepo();
late StreamSubscription _streamSubscription;
DonorsCubit() : super(DonorsInitialState()) {
_streamSubscription =
_firebaseDBRepo.usersStream().listen((List<MyUser> users) {
this.users = users;
});
}
void searchDonors({required String? searchKey}) {
emit(DonorsLoadingState());
List<MyUser> searchedUser = <MyUser>[];
searchedUser.clear();
if (searchKey == null) {
emit(DonorsLoadedState(users: users));
} else {
for (MyUser user in users) {
if (user.username!.toLowerCase().contains(searchKey.toLowerCase())) {
searchedUser.add(user);
}
}
emit(DonorsLoadedState(users: searchedUser));
}
}
@override
Future<void> close() {
_streamSubscription.cancel();
return super.close();
}
}
abstract class DonorsState extends Equatable {
const DonorsState();
}
class DonorsLoadingState extends DonorsState {
@override
List<Object> get props => [];
}
class DonorsInitialState extends DonorsState {
@override
List<Object> get props => [];
}
class DonorsLoadedState extends DonorsState {
final List<MyUser> users;
const DonorsLoadedState({required this.users});
@override
List<Object?> get props => [users];
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您遇到的问题与 provider 包的工作方式有关。为了访问肘,您应该在小部件树上方提供它。现在,您在相同的上下文中提供并聆听肘节。有几种方法可以处理它。
Builder
小部件。我是选项 2 的粉丝,因为更清楚的是您正在拆分代码并在不同的上下文中工作。
BONUS
您可以使用
BlocConsumer
小部件,而不是单独使用BlocListener
和BlocBuilder
:The problem you get is related to how the provider package works. In order to access the cubit, you should provide it above in the widget tree. Now, you provide and listen to the cubit in the same context. There are several ways how you could handle it.
Builder
widget.I am a fan of option 2 since it is more clear that you are splitting your code and working in separate contexts.
BONUS
Instead of using
BlocListener
andBlocBuilder
separately, you could use theBlocConsumer
widget:我有同样的问题,我使用
MultiProvider
列出我的提供程序,如下所示:I have the same problem, I use the
MultiProvider
to list my providers like this: