I am using flutter with nfcmanager as part of a project. I want to use the classes from the real world example of an nfcmanager app that I have tested on my machine and works very well inside my code, so I added a fork of the repo as a dependency, and have successfully imported it in.
However there is an issue when I try to run one of the main classes inside the imported code (TagReadPage):
class TagReadPage extends StatelessWidget {
static Widget withDependency() => ChangeNotifierProvider<TagReadModel>(
create: (context) => TagReadModel(),
child: TagReadPage(),
);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Tag - Read'),
),
body: ListView(
padding: EdgeInsets.all(2),
children: [
FormSection(
children: [
FormRow(
title: Text('Start Session',
style: TextStyle(
color: Theme.of(context).colorScheme.primary)),
onTap: () => startSession(
context: context,
handleTag: Provider.of<TagReadModel>(context, listen: false)
.handleTag,
),
),
],
),
// consider: Selector<Tuple<{TAG}, {ADDITIONAL_DATA}>>
Consumer<TagReadModel>(builder: (context, model, _) {
final tag = model.tag;
final additionalData = model.additionalData;
if (tag != null && additionalData != null)
return _TagInfo(tag, additionalData);
return SizedBox.shrink();
}),
],
),
);
}
}
I can include the other classes being referenced if you need.
When I try to run this class using navigator:
Navigator.push(context,
MaterialPageRoute(builder: (context) => TagReadPage()));
I get a useless error message on the terminal, but inside my app this error comes up:
Error: Could not find the correct Provider<TagReadModel> above this Consumer <TagReadModel> 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 you 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 than Consumer<TagReadModel> us under your MultiProvider/Provider<TagReadModel>, 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(),
child: Text(context.watch<Example>().toString()),)}
Consider using builder like so:
Widget build(BuildContext context){
return Provider<Example>(
create:(_)=>Example(),
return Text(context.watch<Example>().toString()
I ran hot restart and same issue. I know that this might be a simple fix but I am still new to flutter so some advice on how to fix this so I can run the class would be great.
The problem you are experiencing is quite common with the Provider package. As you probably already know, Flutter applications are made up of widgets organised in a tree-like structure. The widget tree.
As a rule of thumb, whenever you use a Consumer
, Selector
or Provider.of(context)
widget, it tries to find the corresponding Provider
by traversing the widget tree up to the root. In your case, the Consumer
widget will not find a corresponding Provider
widget in the widget tree above it until it reaches the top.
To find their position in the widget tree, widgets use the BuildContext
. It is important that the Provider
widget is declared above the widget that contains a dependency on the Provider
and uses a different BuildContext
.
The author of the sample code has a solution for this problem:
static Widget withDependency() => ChangeNotifierProvider<TagReadModel>(
create: (context) => TagReadModel(),
child: TagReadPage(),
);
This method wraps the TagReadPage
instance in a ChangeNotifierProvider
. So if you created it using this static method, the provider should be present in the widget tree. However, you have built the route to this page without using this method. You should change it:
Navigator.push(context, MaterialPageRoute(builder: (context) => TagReadPage()));
to something like:
Navigator.push(context, MaterialPageRoute(builder: (context) => TagReadPage.withDependency()));
Hope this works and helps.