multi Provider doesn't work in material app in flutter?
The following test code work without error, you can test with your case
Use Consumer
to wrap MaterialApp
code snippet
return MultiProvider( providers: [ ChangeNotifierProvider<Posts>( create: (context) => Posts(), ), ChangeNotifierProvider<Settings>( create: (context) => Settings(darkModeEnabled: true), ), ], child: Consumer<Settings>(builder: (_, settings, child) { return MaterialApp( darkTheme: settings.darkModeEnabled ? ThemeData.dark() : ThemeData.light(), debugShowCheckedModeBanner: false, title: 'Blogy', theme: ThemeData( primaryColor: Colors.deepPurple[900], cursorColor: Colors.deepPurple[900], accentColor: Colors.deepPurple[900], fontFamily: 'Ubuntu', ), home: SplashScreen(), ); }), );
full test code
import 'package:flutter/material.dart';import 'package:provider/provider.dart';void main() => runApp(MyApp());class Posts extends ChangeNotifier {}class Settings extends ChangeNotifier { bool darkModeEnabled; Settings({this.darkModeEnabled});}class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MultiProvider( providers: [ ChangeNotifierProvider<Posts>( create: (context) => Posts(), ), ChangeNotifierProvider<Settings>( create: (context) => Settings(darkModeEnabled: true), ), ], child: Consumer<Settings>(builder: (_, settings, child) { return MaterialApp( darkTheme: settings.darkModeEnabled ? ThemeData.dark() : ThemeData.light(), debugShowCheckedModeBanner: false, title: 'Blogy', theme: ThemeData( primaryColor: Colors.deepPurple[900], cursorColor: Colors.deepPurple[900], accentColor: Colors.deepPurple[900], fontFamily: 'Ubuntu', ), home: SplashScreen(), ); }), ); }}class SplashScreen extends StatefulWidget { SplashScreen({Key key}) : super(key: key); //final String title; @override _SplashScreenState createState() => _SplashScreenState();}class _SplashScreenState extends State<SplashScreen> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("test"), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.display1, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), ); }}
This error happens because you are creating your providers and your consumers in the same build
method. This results in them having the same context
, which doesn't have any Provider<Settings>
registered yet. Provider.of<Settings>(context)
is trying to find a Provider<Settings>
above in the widget tree, but there is no such provider there.
Using Consumer
seems like a valid workaround, but recreating the whole MaterialApp on every change might be pretty heavy.
I suggest instead creating separate widgets for providers and the app root:
class AppProviders extends StatelessWidget { final Widget child; AppProviders({this.child}); @override Widget build(BuildContext context) { return MultiProvider( providers: [ ChangeNotifierProvider<Posts>( builder: (context) => Posts(), ), ChangeNotifierProvider<Settings>( builder: (context) => Settings(), ), ], child: child; ); }}
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( darkTheme: Provider.of<Settings>(context).darkModeEnabled ? ThemeData.dark() : ThemeData.light(), debugShowCheckedModeBanner: false, title: 'Blogy', theme: ThemeData( primaryColor: Colors.deepPurple[900], cursorColor: Colors.deepPurple[900], accentColor: Colors.deepPurple[900], fontFamily: 'Ubuntu', ), home: SplashScreen(), ); }}
Then wrap the MyApp
widget in AppProviders
inside the runApp
function.
void main() { runApp( AppProviders( child: MyApp(), ) );}
This ensures that the Providers are registered above your root app widget and that they are visible in its context
.
Alternatively you can declare three widgets where the third one is just AppProviders(child: MyApp())
and call that one in runApp
. Note that creating AppProviders
inside MyApp
's build
method will result in the same error as before, so don't try it that way.