multi Provider doesn't work in material app in flutter? multi Provider doesn't work in material app in flutter? dart dart

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.