Preface:
Provider is Google I/O 2019 conference announced now the official recommendation of state management, I feel very good after learning and using, because it is really easy to use, so write a blog record it!!
Provider GitHub address: github.com/rrousselGit…
Here are two more YouTube videos (the first one just talks about ChangeNotifierProvider, not MultiProvider) :
www.youtube.com/watch?v=xcS…
www.youtube.com/watch?v=d_m…
OK, let’s cut to the chase. Here is a detailed look at how to use providers for state management in Flutter.
I will use a small demo to show you how to use providers for state management. A single Provider and a MultiProvider implementation are used respectively (the first puts two data in the same class, and the second splits the two data into two different classes).
The demo function is very simple, count + switch themes. There are only two pages, and both pages share the same data.
I have uploaded the code for this small demo to GitHub: github.com/MzoneCL/Flu… (MultiProvider) github.com/MzoneCL/Flu… (Single Provider)
Take a look at the rendering:
Let’s take a look at how a single Provider and multiple providers do this.
A single Provider
ChangeNotifierProvider is a kind of Provider. It is convenient to use to manage situations where there is only one shared data class.
Step 1: Add dependencies
Add dependencies to the pubspec.yaml file.
Provider package pub address: pub. Dev /packages/pr…
Step 2: Create shared data classes
class DataInfo with ChangeNotifier {
int _count = 0;
ThemeData _themeData = ThemeData.light();
get count => _count;
get themeData => _themeData;
addCount() {
_count++;
notifyListeners();
}
subCount() {
_count--;
notifyListeners();
}
changeTheme() {
if (_themeData == ThemeData.light()) {
_themeData = ThemeData.dark();
} else{ _themeData = ThemeData.light(); } notifyListeners(); }}Copy the code
Data classes need to be with ChangeNotifier to use notifyListeners() functions to update the interface.
Step 3: Access the data
The Provider can obtain data status in two ways:
- . Use the Provider of < T > (context)
- The use of Consumer
Both methods require a ChangeNotifierProvider() on top:
1. The use of the Provider. Of < T > (context)
For example, the code for specifying the topic section looks like this:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
var dataInfo = Provider.of<DataInfo>(context);
returnMaterialApp( home: MyHomePage(), theme: dataInfo.themeData, ); }}Copy the code
Provider. Of <DataInfo>(context) to obtain the DataInfo instance, specify the specific data class after the of function. You can then access themeData directly through the getter.
2. The use of Consumer
Again, for example, specify the topic part of the code:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
returnConsumer<DataInfo>( builder: (context, dataInfo, _) => MaterialApp( home: MyHomePage(), theme: dataInfo.themeData, ), ); }}Copy the code
Consumer directly wraps widgets that need to use shared data, and Consumer also specifies the type.
Use MultiProvider to manage multiple shared data classes
This can be used with Stream. For Stream related explanations, this guy (@vadaski) has a great post: juejin.cn/post/684490…
Step 1: Add dependencies
Again, add the provider package.
Step 2: Create shared data classes
I created two classes here: CounterBloc and ThemeDataBloc to manage the count and ThemeData, respectively. (The name of the class suggests it borrows from BLoC)
class CounterBloc {
StreamController<int> _streamController;
Stream<int> _stream;
int _count;
CounterBloc() {
_count = 0;
_streamController = StreamController.broadcast();
_stream = _streamController.stream;
}
Stream<int> get stream => _stream;
int get count => _count;
addCounter() {
_streamController.sink.add(++_count);
}
subCounter() {
_streamController.sink.add(--_count);
}
dispose() { _streamController.close(); }}Copy the code
Since CounterBloc is listening on both pages, _streamController needs to be broadcast and supports multiple subscriptions, otherwise an error will be reported.
class ThemeDataBloc {
StreamController<ThemeData> _streamController;
Stream<ThemeData> _stream;
ThemeData _themeData;
ThemeDataBloc() {
_themeData = ThemeData.light();
_streamController = StreamController();
_stream = _streamController.stream;
}
Stream<ThemeData> get stream => _stream;
changeTheme() { _themeData = _themeData == ThemeData.light()? ThemeData.dark():ThemeData.light(); _streamController.sink.add(_themeData); }dispose() { _streamController.close(); }}Copy the code
Because of the Stream used here, there is no need for the ChangeNotifier as above.
Step 3: Place the MultiProvider at the top of your application
MultiProvider has a mandatory parameter: providers. We need to pass it a list of providers. In this way, we can access related shared data in all child widgets.
main() {
var counterBloc = CounterBloc();
var themeDataBloc = ThemeDataBloc();
runApp(MultiProvider(providers: [
Provider<CounterBloc>.value(value: counterBloc),
Provider<ThemeDataBloc>.value(value: themeDataBloc),
], child: MyApp()));
}
Copy the code
Step 4: Access the data
Use provider.of <T>(context) to get data of the specified type.
Again, take the code that specifies a topic:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder(
builder: (context, snapshot) {
returnMaterialApp( home: MyHomePage(), theme: snapshot.data, ); }, initialData: ThemeData.light(), stream: Provider.of<ThemeDataBloc>(context).stream, ); }}Copy the code
Again, you need to specify the type after the of function to find the specific Provider.
Okay, that’s the basic use of providers for state management in Flutter!