Google2019I/O was recommended by Google, the original Google provide was deprecated, and uses InheritedWidget like most state management. Based on the Provider3.0 chapter on Flutter State Management Provider
###ChangeNotifierProvider() this is similar to scoped_model, except that it uses mixins. Scoped_model uses an inheritance. Status updates are then notified by calling notifyListeners(). Like ValueListenableProvider also has two ways, ChangeNotifierProvider () and ChangeNotifierProvider value (), The difference is that ChangeNotifierProvider() automatically calls Its Dispose () method in ChangeNotifier to release some resources when it is destroyed. Next, use ChangeNotifierProvider() to write a requirement. Just like wechat, switch the interface with four buttons at the bottom, then jump to the second-level page and click the second-level page button to control the switch of the first-level page.
import "package:flutter/material.dart";
import 'index_page.dart';
import 'package:provider/provider.dart';
import 'index_provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
//MultiProvider can add multiple state management
// Wrapped outside the MaterialApp, scope is global
return MultiProvider(
providers: [
// ChangeNotifierProvider is used because dispose() method is automatically called to help me free resources
ChangeNotifierProvider(builder: (_) => IndexProvider()),
// ChangeNotifierProvider.value(value: IndexProvider())
],
child: MaterialApp(
title: "Flutter Demo", theme: ThemeData(primarySwatch: Colors.blue), home: IndexPage(), ), ); }}Copy the code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'index_provider.dart';
class IndexPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<IndexProvider>(
// Optimization: ViewPage subpages do not go build when state changes
child: PageView(
physics: NeverScrollableScrollPhysics(), // Disable scrolling
// Do not listen for changes after getting pageController
controller: Provider.of<IndexProvider>(context,listen: false).pageController,
children: [ChildPage("Page one"), ChildPage("Page two"), ChildPage("Page three")],
),
builder: (context, indexProvider, child) {
return Scaffold(
body: child,
bottomNavigationBar: BottomNavigationBar(
onTap: (index) {
indexProvider.index = index;
},
currentIndex: indexProvider.index,
items: [
BottomNavigationBarItem(icon: Icon(Icons.android), title: Text("android")),
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text("home")),
BottomNavigationBarItem(icon: Icon(Icons.person), title: Text("person")), ]), floatingActionButton: FloatingActionButton(onPressed: () { Navigator.push(context, MaterialPageRoute(builder: (context) => SecondPage())); })); }); }}class ChildPage extends StatefulWidget {
final String title;
ChildPage(this.title);
@override
_ChildPageState createState() => _ChildPageState();
}
class _ChildPageState extends State<ChildPage> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
void initState() {
super.initState();
print("${widget.title}: initState");
}
@override
Widget build(BuildContext context) {
super.build(context);
print("${widget.title}: build");
return Scaffold(
backgroundColor: widget.title == 'Page one'
? Colors.red.withOpacity(0.5)
: widget.title == 'Page 2'
? Colors.yellow.withOpacity(0.5)
: Colors.green.withOpacity(0.5), appBar: AppBar(title: Text(widget.title)), body: Center(child: Text(widget.title)), ); }}class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FlatButton(onPressed: () => changePageIndex(context, 0), child: Text(Switch "1"), color: Colors.red),
FlatButton(onPressed: () => changePageIndex(context, 1), child: Text("Switch 2"), color: Colors.yellow),
FlatButton(onPressed: () => changePageIndex(context, 2), child: Text("Switch 3"), color: Colors.green),
],
),
),
);
}
changePageIndex(context, int index) {
Provider.of<IndexProvider>(context, listen: false).index = index; }}Copy the code
import 'package:flutter/material.dart' show ChangeNotifier, PageController;
class IndexProvider with ChangeNotifier {
int _index = 0;
PageController pageController;
int get index => _index;
set index(int value) {
_index = value;
pageController.jumpToPage(this._index);
notifyListeners();
}
IndexProvider() {
pageController = PageController(initialPage: _index);
}
// Using the ChangeNotifierProvider calls the Dispose () method on the destruction to release the resource
@override
voiddispose() { pageController? .dispose();super.dispose(); }}Copy the code
The source code
# # # StreamProvider three methods to use, it is StreamProvider, StreamProvider. Value () and StreamProvider controller (), StreamProvider and StreamProvider. Value is almost the same (), StreamProvider. Controller () there is a little different, first above:
class StreamPage extends StatefulWidget {
@override
_StreamPageState createState() => _StreamPageState();
}
class _StreamPageState extends State<StreamPage> {
StreamController _streamController;
int _count=4;
@override
void initState() {
super.initState();
_streamController = StreamController<int> (); }@override
void dispose() {
_streamController.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("StreamProvider")),
// body: StreamProvider
.value(
// value: _streamController.stream,
// initialData: _count,
//// catchError: ,
// child: MyText(),
/ /),
body: StreamProvider<int>(
builder: (_) => _streamController.stream,/ / builder is equal to the value
initialData: _count,//initialData: initialization value, not null
catchError: (BuildContext context, Object error) {
CatchError: called when an exception occurs, returns the same value as the StreamController paradigm
// If catchError is not written, the screen will be red when an error is reported
print("Ha, ha:${error.toString()}");
return 10000;
},
child: MyText(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
if(_count<8) _streamController.sink.add(++_count);
else _streamController.sink.addError("Abnormal."); }, child: Icon(Icons.add), ), ); }}class MyText extends StatelessWidget {
@override
Widget build(BuildContext context) {
final count = Provider.of<int>(context);
return Center(child: Text("$count")); }}Copy the code
StreamProvider. Controller () code:
class StreamPage extends StatefulWidget {
@override
_StreamPageState createState() => _StreamPageState();
}
class _StreamPageState extends State<StreamPage> {
StreamController _streamController;
int _count = 4;
@override
void initState() {
super.initState();
_streamController = StreamController<int> (); }@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("StreamProvider")),
body: StreamProvider<int>.controller(
builder: (_) => _streamController,
initialData: _count, //initialData: initialization value, not null
catchError: (BuildContext context, Object error) {
CatchError: called when an exception occurs, returns the same value as the StreamController paradigm
// If catchError is not written, the screen will be red when an error is reported
print("Ha, ha:${error.toString()}");
return 10000;
},
child: MyText(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
if (_count < 8)
_streamController.sink.add(++_count);
else
_streamController.sink.addError("Abnormal.");// Manually throw an exception}, child: Icon(Icons.add), ), ); }}class MyText extends StatelessWidget {
@override
Widget build(BuildContext context) {
final count = Provider.of<int>(context);
return Center(child: Text("$count")); }}Copy the code
Huh? ! Looks no different, but you carefully look at StreamProvider. The controller code inside I don’t have to rewrite the dispose () method, Reason is StreamProvider. The controller will help us in StreamController destruction is call the close () method. Enter the source code can be seen
Conclusion:
- The difference between Provider() and provider.value () is that Provider() has a dispose argument that passes a method to help release the resource when it is destroyed. They do not provide state change listeners.
- ValueListenableProvider. Value () and ValueListenableProvider () is the same, only support a status value.
- ChangeNotifierProvider. Value () and ChangeNotifierProvider () is the difference between ChangeNotifierProvider () at the time of destruction to invoke the dispose () to release resources, You can use the ChangeNotifierProvider when you need to use multiple state values.
- ListenableProvider code didn’t write it, it is the parent class ChangeNotifierProvider, ListenableProvider. Value () and ChangeNotifierProvider value () function, ListenableProvider() is similar to ValueListenableProvider(), but ListenableProvider() has a dispose parameter that needs to be passed by itself.
- StreamProvider. Value () and StreamProvider () is essentially the same, all need to manually close the flow, and StreamProvider. Controller () automatically shut down stream.
- MultiProvider() can provide multiple states.
- Provider.of() is used to get the state in the Widget tree, The listen parameter in provider.of () controls whether to listen for state changes when using ValueListenableProvider, ChangeNotifierProvider, and StreamProvider.
- Consumer() and provider.of () are both used to get state in the Widget tree, but Consumer can be used where there is no context or to optimize performance, and the child argument can be used to narrow the scope of redrawing.
- The state management is wrapped outside of the MaterialApp() scope and is global, while other scopes are in this page or child widgets of this page;
#### if write wrong place welcome to point out!