Provider Scope
MaterialApp
> provider(Screen A)
> Screen B
If Provider is instantiated in Screen A, it won’t be accessible in Screen B after a Navigator.push from A → B.
Why?
Because Provider is an InheritedWidget and Navigator uses MaterialApp context outside its Screen A context scope. (See Details below.)
Fix
Moving Provider up to a common-parent, MaterialApp context, allows both Screen A and B to inherit its state/context.
provider(MaterialApp)
> Screen A
> Screen B
Example
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
/// wrap MaterialApp in Provider widget
return ChangeNotifierProvider(
create: (context) => ColorModel(), // ← create/init your state model
child: MaterialApp(
home: ScreenA()
),
);
}
}
Details
Provider
-
Provideris based onInheritedWidget. Only child widgets can inherit parent widget’s state.Providerneeds to be the root widget for any widget tree that wants access to your “provided” state object.
Navigator
Navigator.push(context)on Screen A doesn’t use thecontextfrom Screen A.- It uses
contextfromMaterialApp.
- It uses
Navigator.push(context)is actuallyNavigator.of(context).pushNavigator.of(context)means: search up this context hierarchy until you find a context that instantiated a Navigator- A default
Navigatoris instantiated inMaterialApp. - Unless you explicitly create/use a different
Navigator, you’re using the default. Navigator‘scontextis that ofMaterialApp.
- A default
- Screen B will get that context (of
MaterialApp), not the context of Screen A.- B is a sibling of A, not its child.
- B does not inherit from A, even though it appears “instantiated” inside
contextA. - Screen B is a child of
MaterialAppcontext, not of Screen Acontext. Providercontextscope, if defined in Screen A, doesn’t cover Screen B
Screen A → B
Navigator.push(context, MaterialPageRoute(builder: (context) => ScreenB()))
is actually:
Navigator.of(context).push(MaterialPageRoute(builder: (context) => ScreenB()))
which is like:
Navigator.of(MaterialApp).push(
MaterialPageRoute(builder: (MaterialAppContext) => ScreenB())
)
So Screen B is under MaterialApp context, not under Screen A context and therefore has no access to Screen A Provider and its context.
See this answer for a code sample to a similar question about Provider.