若是對Provider的使用已經很熟練,能夠跳過這部份內容,直接看過程分析部分 Flutter狀態管理Provider(二)過程分析html
Demo代碼倉庫 入口:main_provider.dartgit
[Provider](https://github.com/rrousselGit/provider)
簡單翻譯來講,Provider:依賴注入與狀態管理的結合,而且對外提供Widget使用。使用widget代替純Dart對象,好比說Stream。由於widget簡單,強大且可擴展。使用Provider,能夠保證:可維護性(強制的單向數據流),可測試性,健壯性等等。
A mixture between dependency injection (DI) and state management, built with widgets for widgets.It purposefully uses widgets for DI/state management instead of dart-only classes like Stream.
The reason is, widgets are very simple yet robust and scalable.
By using widgets for state management, provider can guarantee:
複製代碼
若是說頁面是靜態,拿到數據,渲染完就完事了.壓根就不須要狀態管理。 不幸的是,頁面不可能全是靜態。頁面須要響應數據變化(網絡數據?用戶操做產生的數據?),更新UI。同時,數據變化的影響,不單單是組件內,還有多是頁面內其餘組件,甚至於應用內其餘頁面github
數據即爲狀態。從數據變化到通知界面更新的過程,咱們稱之爲狀態管理 狀態管理要儘量的把這個過程獨立出來,讓動態界面如同靜態頁面通常簡單。redux
- setState
- FutureBuilder/StreamBuilder/BLoc
- Provider/ScopedModel
- redux/Fish-redux
複製代碼
有了狀態管理的介紹,咱們能夠參考Provider,經過手上現有的組件,實現一個簡易版的Provider。要用到的系統組件:bash
狀態管理最基礎的一個實現markdown
class _SetStateDemoWidgetState extends State<SetStateDemoWidget> { int count = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(setStateDemoTitle),), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text("計數:$count"), RaisedButton( child: Text("increment"), onPressed: () => setState(() => count++), ) ], ), ), ); } } 複製代碼
用CountProvider繼承InheritedWidget來保存數據。 經過context.getElementForInheritedWidgetOfExactType拿到CountProvider中的數據。 這個context必定要注意,只能用CountProvider子widget的BuildContext。CountProvider的查找是經過context往上的。 注意這個地方,咱們只是單純的拿數據,尚未用到InheritedWidget能夠控制子widget從新構建的功能。網絡
///首先咱們要有個地方存放咱們的數據 class CountProvider extends InheritedWidget { final int count; CountProvider({Key key, this.count, Widget child}) : super(key: key, child: child); @override bool updateShouldNotify(CountProvider old) { return true; } } class ProviderDemoWidget1 extends StatefulWidget { ProviderDemoWidget1({Key key}) : super(key: key); @override _ProviderDemoWidget1State createState() => _ProviderDemoWidget1State(); } class _ProviderDemoWidget1State extends State<ProviderDemoWidget1> { int _count = 0; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(providerDemoTitle1), ), body: CountProvider( count: _count, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Builder( builder: (context2) { CountProvider provider = context2 .getElementForInheritedWidgetOfExactType<CountProvider>() .widget; return Text("計數:${provider.count}"); }, ), /// 讀取和顯示計數 RaisedButton( child: Text("increment"), onPressed: () => setState(() => _count++), ), Text(providerDemoIntroduction1), ], ), ), ), ); } } 複製代碼
咱們先看效果圖,咱們看到有三種場景。只有依賴的組件更新了UI。app
class CountModel extends ChangeNotifier { int count; CountModel(this.count); void increment() { count++; notifyListeners(); } } 複製代碼
class Provider<T extends ChangeNotifier> extends InheritedWidget { final T model; Provider({Key key, this.model, Widget child}) : super(key: key, child: child); static T of<T extends ChangeNotifier>(BuildContext context, bool depend) { if (depend) { return context.dependOnInheritedWidgetOfExactType<Provider>().model; } else { Provider provider = context.getElementForInheritedWidgetOfExactType<Provider>().widget; return provider.model; } } @override bool updateShouldNotify(Provider old) { return true; } } 複製代碼
class ChangeNotifierProvider<T extends ChangeNotifier> extends StatefulWidget { final Widget child; final T model; ChangeNotifierProvider({this.child, this.model}); @override _ChangeNotifierProviderState createState() => _ChangeNotifierProviderState(); } class _ChangeNotifierProviderState extends State<ChangeNotifierProvider> { _ChangeNotifierProviderState(); _update() { setState(() => {}); } @override void initState() { super.initState(); widget.model.addListener(_update); } @override void dispose() { super.dispose(); widget.model.removeListener(_update); } @override Widget build(BuildContext context) { return Provider( model: widget.model, child: widget.child, ); } } 複製代碼
class ProviderDemoWidget3 extends StatefulWidget { ProviderDemoWidget3({Key key}) : super(key: key); @override _ProviderDemoWidget3State createState() => _ProviderDemoWidget3State(); } class _ProviderDemoWidget3State extends State<ProviderDemoWidget3> { CountModel _countModel = CountModel(0); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(providerDemoTitle3), ), body: ChangeNotifierProvider<CountModel>( model: _countModel, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Builder(builder: (context1) { return Text( "計數:${Provider.of<CountModel>(context1, true).count}(有依賴狀況)"); }), Builder(builder: (context2) { return Text( "計數:${Provider.of<CountModel>(context2, false).count}(無依賴狀況)"); }), RaisedButton( child: Text("increment"), onPressed: () => _countModel.increment()), Text(providerDemoIntroduction3), ], ), ), ), ); } } 複製代碼
上一個示例中CountModel不具備通用性,因此咱們寫一個泛型版本ide
class Provider<T extends ChangeNotifier> extends InheritedWidget { final T model; Provider({Key key, this.model, Widget child}) : super(key: key, child: child); static T of<T extends ChangeNotifier>(BuildContext context, bool depend) { if (depend) { return context.dependOnInheritedWidgetOfExactType<Provider>().model; } else { Provider provider = context.getElementForInheritedWidgetOfExactType<Provider>().widget; return provider.model; } } @override bool updateShouldNotify(Provider old) { return true; } } 複製代碼
class ChangeNotifierProvider<T extends ChangeNotifier> extends StatefulWidget { final Widget child; final T model; ChangeNotifierProvider({this.child, this.model}); @override _ChangeNotifierProviderState createState() => _ChangeNotifierProviderState(); } class _ChangeNotifierProviderState extends State<ChangeNotifierProvider> { _ChangeNotifierProviderState(); _update() { setState(() => {}); } @override void initState() { super.initState(); widget.model.addListener(_update); } @override void dispose() { super.dispose(); widget.model.removeListener(_update); } @override Widget build(BuildContext context) { return Provider( model: widget.model, child: widget.child, ); } } 複製代碼
class CountModel extends ChangeNotifier { int count; CountModel(this.count); void increment() { count++; notifyListeners(); } } class ProviderDemoWidget3 extends StatefulWidget { ProviderDemoWidget3({Key key}) : super(key: key); @override _ProviderDemoWidget3State createState() => _ProviderDemoWidget3State(); } class _ProviderDemoWidget3State extends State<ProviderDemoWidget3> { CountModel _countModel = CountModel(0); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(providerDemoTitle3), ), body: ChangeNotifierProvider<CountModel>( model: _countModel, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Builder(builder: (context1) { return Text( "計數:${Provider.of<CountModel>(context1, true).count}(有依賴狀況)"); }), Builder(builder: (context2) { return Text( "計數:${Provider.of<CountModel>(context2, false).count}(無依賴狀況)"); }), RaisedButton( child: Text("increment"), onPressed: () => _countModel.increment()), Text(providerDemoIntroduction3), ], ), ), ), ); } } 複製代碼
咱們發現與上一個示例的簡易版Provider上的使用方法是一致的。 正如介紹所描述的很是簡單。固然了Provider庫,可維護性,可測試性,可擴展性遠比咱們所寫的強大。oop
class ProviderDemoWidget4 extends StatefulWidget { ProviderDemoWidget4({Key key}) : super(key: key); @override _ProviderDemoWidget4State createState() => _ProviderDemoWidget4State(); } class _ProviderDemoWidget4State extends State<ProviderDemoWidget4> { CountModel _countModel = CountModel(0); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(providerDemoTitle4), ), body: ChangeNotifierProvider.value( value: _countModel, child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Consumer<CountModel>( builder: (contextC, model, child) { return Text("計數:${model.count}(有依賴狀況)"); }, ), Builder(builder: (context2) { return Text( "計數:${Provider.of<CountModel>(context2, listen: false).count}(無依賴狀況)"); }), RaisedButton( child: Text("increment"), onPressed: () => _countModel.increment()), Text(providerDemoIntroduction4), ], ), ), ), ); } } class CountModel extends ChangeNotifier { int count; CountModel(this.count); void increment() { count++; notifyListeners(); } } 複製代碼
到此爲止,咱們也就瞭解了Provider的基本原理和基本使用。 可咱們的征程纔開始。知其然,更要知其因此然。接下來,咱們從setState開始一步步分析Provider狀態管理的過程。