⚠️Flutter的 狀態管理⚠️

👏歡迎前往本人的GitHub查看更多內容。點擊前往GitHubreact

1 對於狀態管理的理解

最近項目開發完成後,沒有什麼任務安排,就本身對項目進行了查缺補漏。若是說flutter開發中最不可避免的話,確定是狀態管理啦。咱們本身的項目當中用的是Provider來進行管理的,本身其實對於狀態管理的基礎仍是有一點模糊,粗淺的理解就是:避免對頁面不停的build,要進行鍼對性的刷新,(列入:更新一個text也將整個頁面build一次浪費性能。)git



1.0 那咱們來言歸正傳說一說比較正確的理解吧,避免我在這裏誤人子弟。

1.狀態管理的目的就是爲了讓界面與業務分離。
2.當咱們的應用功能複雜多樣的時候,應用程序將會有幾十個甚至上百個狀態,這時候咱們須要對狀態進行合理有效的管理。
複製代碼

不少從命令式編程框架(Android或iOS原生開發者)轉成聲明式編程(Flutter、Vue、React等)剛開始並不適應,由於須要一個新的角度來考慮APP的開發模式。

Flutter做爲一個現代的框架,是聲明式編程的:

在編寫一個應用的過程當中,咱們有大量的狀態須要來進行管理,而正是對這些State的改變,來更新界面的刷新:




2 狀態管理框架

能夠經過以下方式來進行狀態管理

1.setState :
最重要的方式 setState,支持規模較小的程序足夠了,全部其它方式最終都須要調用 setState。

2.Function callback
Dart Function 足夠靈活,還支持模版參數。
typedef FooChanged = void Function(int);
typedef ValueChanged<T> = void Function(T value);
單向變動通知,能夠和ObserverList結合支持多個訂閱者。
Flutter 內置 ChangeNotifier, ValueNotifier 均可以認爲是相似方案。

3.Delegate
能夠認爲是多個回調函數,其餘語言裏都有相似模式,名稱彷佛來源於 Objective-C。實際例子
abstract class SpiderDelegate {
  /// category is null, crawl book whole site
  /// category not null, crawl book under the category
  void onBook(Book book, {Site site, Category category});

  void onChapter(Book book, Chapter chapter);
}


4.Sigslot
源自 Qt 裏的經典編程模式,Dart 能夠輕易實現。這種方式在 Flutter 裏可能根本不會有太多應用,可是因爲 Sigslot 在 C++ 領域具備舉足輕重的地位,屬於界面數據和邏輯解耦合的王者,boost::signal(2)就是明證,在這裏列出純屬湊數(本人也實現了一個)。
typedef ValueCallback<E> = void Function(E value);
abstract class Signable<E> {
  // Signable<bool> someValue;
  /// Register a closure to be called when the object notifies its listeners.
  void connect(ValueCallback<E> listener);

  /// Remove a previously registered closure from the list of closures that the
  /// object notifies.
  void disconnect(ValueCallback<E> listener);

  /// sink value changed
  void emit(E value);
}

使用方法相似
Signal<String> signalString;
signalString.connect((String str) {
  // got the `str` changed here
});

複製代碼


2.1 scoped_model

Scoped_model是一個dart第三方庫,提供了讓您可以輕鬆地將數據模型從父Widget傳遞到它的後代的功能。此外,它還會在模型更新時從新渲染使用該模型的全部子項。
它直接來自於Google正在開發的新系統Fuchsia核心Widgets 中對Model類的簡單提取,做爲獨立使用的獨立Flutter插件發佈。

Scoped model使用了觀察者模式,將數據模型放在父代,後代經過找到父代的model進行數據渲染,最後數據改變時將數據傳回,父代再通知全部用到了該model的子代去更新狀態。
複製代碼


2.2 Redux

Redux是一種單向數據流架構,能夠輕鬆開發,維護和測試應用程序。
複製代碼

咱們在Redux中,全部的狀態都儲存在Store裏。這個Store會放在App頂層。
View拿到Store儲存的狀態(State)並把它映射成視圖。View還會與用戶進行交互,用戶點擊按鈕滑動屏幕等等,這時會由於交互須要數據發生改變。
Redux讓咱們不能讓View直接操做數據,而是經過發起一個action來告訴Reducer,狀態得改變啦。
這時候Reducer接收到了這個action,他就回去遍歷action表,而後找到那個匹配的action,根據action生成新的狀態並把新的狀態放到Store中。
Store丟棄了老的狀態對象,儲存了新的狀態對象後,就通知全部使用到了這個狀態的View更新(相似setState)。這樣咱們就可以同步不一樣view中的狀態了。
複製代碼


2.3 BLoC

BLoC是一種利用reactive programming方式構建應用的方法,這是一個由流構成的徹底異步的世界。
複製代碼

* 用StreamBuilder包裹有狀態的部件,streambuilder將會監聽一個流
* 這個流來自於BLoC
* 有狀態小部件中的數據來自於監聽的流。
* 用戶交互手勢被檢測到,產生了事件。例如按了一下按鈕。
* 調用bloc的功能來處理這個事件
* 在bloc中處理完畢後將會吧最新的數據add進流的sink中
* StreamBuilder監聽到新的數據,產生一個新的snapshot,並從新調用build方法
* Widget被從新構建
複製代碼


2.4 RxDart

RxDart是基於ReactiveX標準API的Dart版本實現,由Dart標準庫中Stream擴展而成。所以,RxDart與Dart的相關術語稍有區別:

Dart	RxDart
StreamController	Subject
Stream	Observable
Observable等同於Stream,Subject等同於StreamController,前者均由後者繼承而來。
不一樣於Dart,RxDart提供了三種StreamController的變體來應用到不一樣的場景:

PublishSubject
BehaviorSubject
ReplaySubject
複製代碼


2.5 Fish-Redux【推薦👍】

Fish Redux 是一個基於 Redux 數據管理的組裝式 flutter 應用框架, 它特別適用於構建中大型的複雜應用。它的特色是配置式組裝。
一方面咱們將一個大的頁面,對視圖和數據層層拆解爲互相獨立的 Component|Adapter,上層負責組裝,下層負責實現;
另外一方面將 Component|Adapter 拆分爲 View,Reducer,Effect 等相互獨立的上下文無關函數。
因此它會很是乾淨,易維護,易協做。
Fish Redux 的靈感主要來自於 Redux, Elm, Dva 這樣的優秀框架。而 Fish Redux 站在巨人的肩膀上,將集中,分治,複用,隔離作的更進一步。
複製代碼


2.7 Provide

和Scoped_model同樣,Provide也是藉助了InheritWidget,將共享狀態放到頂層MaterialApp之上。底層部件經過Provier獲取該狀態,並經過混合ChangeNotifier通知依賴於該狀態的組件刷新。
Provide還提供了Provide.stream,讓咱們可以以處理流的方式處理數據,不過目前還有一些問題,不推薦使用。
複製代碼


2.6 Provider 【推薦👍👍👍】

2019 Google I/O 大會上重磅消息出了支持 flutter_web 以外,另外一個即是棄用以前的狀態管理 Provide,轉而推薦類似的庫 Provider;雖然只有一個字母之差使用方式差異卻很大;小菜初步學習一下新的狀態管理庫 Provider;
 Flutter 針對不一樣類型對象提供了多種不一樣的 Provider;Provider 也是藉助了 InheritWidget,將共享狀態放到頂層 MaterialApp 之上;

複製代碼



3 實際開發中遇到的坑

3.1 ⚠️Provider中如何抉擇 Consumer 仍是 Selector

當咱們須要更新頁面的時候,咱們會用notifyListeners();
可是若是咱們用Consumer來包裹一個listview咱們打印會發現已經build過的item都會從新的build一次。
其實這樣有一點不合理,由於咱們只須要更新的是其中一個item。
這時候若是咱們用Selector來處理的話就會發現大有不一樣。它只會build咱們須要更新的那個item這樣的話就更加合理。
可是使用Selector的話,須要注意的是shouldRebuild用什麼來決定是否從新build
複製代碼

3.2 ⚠️Provider使用Provider.of(context) 獲取頂層數據的坑

若是咱們APage使用Provider.of(context) 獲取頂層數據,而後BPage對數據進行了更改,其實會影響到APage的而後會從新運行其 build。
其實咱們command點擊of進到底層代碼發現,除了context之外還有一個參數listen。
若是咱們在APage設置listen:false,這樣就不會由於BPage的操做影響到APage了
複製代碼

3.3 ⚠️SingleTickerProviderStateMixin與TickerProviderStateMixin的坑

當使用vsync: this的時候,State對象必須with SingleTickerProviderStateMixin或TickerProviderStateMixin

首先咱們要搞清楚SingleTickerProviderStateMixin於TickerProviderStateMixin的區別:
TickerProviderStateMixin適用於多AnimationController的狀況
SingleTickerProviderStateMixin適用於單個AnimationController的狀況

其實非必須用TickerProviderStateMixin,建議是用SingleTickerProviderStateMixin的。
1.由於若是 APage 使用 with TickerProviderStateMixin,當從APage 跳轉到BPage的時候或從BPage返回到APage的時候你打印會發現都調用了build方法。
2.若是不使用 with TickerProviderStateMixin,當從APage 跳轉到BPage的時候或從BPage返回到APage的時候都不會調用了build方法。
複製代碼





複製代碼

參考來源:github

State managementweb

Flutter移動應用:狀態管理編程

Flutter | 狀態管理指南篇——Providerredux

八種 Flutter 狀態管理-深刻評論bash

相關文章
相關標籤/搜索