Flutter的不少靈感來自於React,它的設計思想是數據與視圖分離,由數據映射渲染視圖。因此在Flutter中,它的Widget是immutable的,而它的動態部分所有放到了狀態(State)中。react
假如你曾進行過react開發,也許你一下會想到Redux。flutter有相似redux的狀態管理的庫嗎?答案是確定的,可是有關在flutter中使用redux的應用實踐咱們會在以後的文章中進行介紹。git
這個系列將會從這幾個狀態管理方案進行深刻研究:github
今天要和你們分享的是第一篇,使用Scoped_model進行狀態管理。redux
在咱們一開始構建應用的時候,也許很簡單。咱們有一些狀態,直接把他們映射成視圖就能夠了。這種簡單應用可能並不須要狀態管理。架構
可是隨着功能的增長,你的應用程序將會有幾十個甚至上百個狀態。這個時候你的應用應該會是這樣。app
這時候,咱們便迫切的須要一個架構來幫助咱們理清這些關係,狀態管理框架應運而生。框架
Scoped_model是一個dart第三方庫,提供了讓您可以輕鬆地將數據模型從父Widget傳遞到它的後代的功能。此外,它還會在模型更新時從新渲染使用該模型的全部子項。less
它直接來自於Google正在開發的新系統Fuchsia核心Widgets 中對Model類的簡單提取,做爲獨立使用的獨立Flutter插件發佈。ide
Scoped model使用了觀察者模式,將數據模型放在父代,後代經過找到父代的model進行數據渲染,最後數據改變時將數據傳回,父代再通知全部用到了該model的子代去更新狀態。post
而咱們則須要將它們放在頂層入口MaterialApp之上,這樣就能進行全局的狀態管理了。
這裏咱們以一個最簡單的CountApp舉例,詳細介紹Scoped_model的用法。該項目完整代碼已放在github倉庫。
這是一個在不一樣頁面使用Scoped共享狀態信息的app。這兩個頁面都依賴於一個數字,這個數字會隨着咱們按下按鈕的次數而增長。
在pubspec中添加scoped_model的依賴。
在Scoped中,Model是一個只包含與狀態相關信息的單位。咱們應該把狀態數據與操做數據的方法抽象出來封裝到Model中。
import 'package:scoped_model/scoped_model.dart';
class CountModel extends Model{
int _count = 0;
get count => _count;
void increment(){
_count++;
notifyListeners();
}
}
複製代碼
//建立頂層狀態
CountModel countModel = CountModel();
@override
Widget build(BuildContext context) {
return ScopedModel<CountModel>(
model: countModel,
child: new MaterialApp(
home: TopScreen(),
),
);
}
複製代碼
咱們能夠從前面的演示圖片中看出,一共有兩個頁面,都使用了同一個model。 Scoped_model提供了兩種方式在子頁面中獲取model。咱們先來介紹第一種,使用ScopedModelDescendant獲取model。
@override
Widget build(BuildContext context) {
return ScopedModelDescendant<CountModel>(
builder: (context,child,model){
return Scaffold(
body: Center(
child: Text(
model.count.toString(),
style: TextStyle(fontSize: 48.0),
),
),
);
},
);
}
複製代碼
floatingActionButton: new FloatingActionButton(
onPressed: () => model.increment(),
tooltip: 'Increment',
child: new Icon(Icons.add),
)
複製代碼
第二種獲取model的方式——使用ScopedModel.of
final countModel = ScopedModel.of<CountModel>(context);
countModel.increment();
複製代碼
或者在Model中重寫of方法
class CountModel extends Model{
int _count = 0;
get count => _count;
void increment(){
_count++;
notifyListeners();
}
//重寫of方法
CountModel of(context) =>
ScopedModel.of<CountModel>(context);
}
複製代碼
而後直接經過CountModel獲取model實例
final countModel2 = CountModel().of(context);
複製代碼
這種方式彷佛讓咱們的代碼有更好的可閱讀性。
【注意:】咱們在使用第二種方式的時候,rebuildOnChange屬性默認爲false,因此會致使沒法刷新(同步)狀態的狀況發生,須要手動指定rebuildOnChange:true。這裏要很是感謝@榮毅coolboy同窗的分享!
要解決這個問題很簡單,使用Mixin!
class MainModel extends Model with AModel,BModel,CModel{}
複製代碼
而後將MainModel放在頂層便可。 這裏有一個比較完整的使用ScopedModel管理狀態的應用,詳細用法可參考該項目。
在不一樣頁面間的數據傳遞使用了InheritedWidget。
因爲Model必須繼承至Model類,因此它就具備了侵入性。之後假如不用scoped進行狀態管理那麼必然會帶來須要更改多處代碼的狀況。這並非咱們但願看到的結果。
在flutter中,Scoped_model是一種很是簡單易上手,並能保持代碼高可閱讀性的一種新的狀態管理方式,值得各位去嘗試一下!
本次所用到的代碼已經上傳Github: github.com/Vadaski/Vad…
若是您對scoped還有任何疑問或者文章的建議,歡迎在下方評論區以及個人郵箱1652219550a@gmail.com與我聯繫,我會及時回覆!
下一章咱們將探索Redux在Flutter中的實踐,敬請關注。