當咱們使用編譯器建立一個新Flutter應用的時候,咱們能夠在主界面看到兩個小部件StatelessWidget和StatefulWidget。這是兩個最多見使用最頻繁的小部件了。前端
假如咱們要實現以下圖的功能,點擊加一。若是使用StatelessWidget,會發現點擊的時候count是加一了,可是界面沒有刷新。應該使用StatefulWidget,當count加一的時候經過setState(() { _count++;});
方法來改變count的值,這時候就發現界面能夠刷新了。git
好比github
import 'package:flutter/material.dart';
class StateManagerDemo extends StatefulWidget {
@override
_StateManagerDemoState createState() => _StateManagerDemoState();
}
class _StateManagerDemoState extends State<StateManagerDemo> {
int _count = 0;
void countCallBack(){
setState(() {
_count++;
});
debugPrint('$_count');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('StateManagerDemo'),
elevation: 0.0,
),
body: Counter0(_count),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: countCallBack,
),
);
}
}
//------
class Counter0 extends StatelessWidget {
final int count;
Counter0(this.count);
@override
Widget build(BuildContext context) {
return Center(
child: Chip(
label: Text('$count'),
),
);
}
}
//-----
class Counter extends StatelessWidget {
final int count;
final VoidCallback voidCallback;
Counter(this.count,this.voidCallback);
@override
Widget build(BuildContext context) {
return Center(
child: ActionChip(
label: Text('$count'),
onPressed: voidCallback,
),
);
}
}
複製代碼
上面的代碼中,StateManagerDemo有兩個子部件Counter0和Counter。當咱們點擊按鈕的時候,_count的值++,而後傳遞給子部件。bash
Counter0是直接接受父部件傳過來的參數。網絡
Counter不只接收父部件傳過來的參數,還有一個回調。這樣點擊它的時候,會執行父部件中的回調方法,也能改變自身的顯示。app
上面的狀況是隻有一層,Counter小部件中使用了父部件的count這個變量,假如Counter沒有用到這個變量而是它的子類用到了這個變量,咱們還要一層一層的傳下去嗎,這有點麻煩啊,這時候可使用InheritedWidget這個類來管理。less
import 'package:flutter/material.dart';
//使用InheritedWidget來管理狀態,
class ContentProvider extends InheritedWidget {
final int count;
final VoidCallback countCallBack;
final Widget child;
const ContentProvider({
this. count,
this. countCallBack,
this. child,
}): assert(child != null),
super(child: child);
static ContentProvider of(BuildContext context) {
return context.inheritFromWidgetOfExactType(
ContentProvider) as ContentProvider;
}
//是否通知繼承該小部件的小部件更新
@override
bool updateShouldNotify(ContentProvider old) {
return true;
}
}
class StateManagerDemo extends StatefulWidget {
@override
_StateManagerDemoState createState() => _StateManagerDemoState();
}
class _StateManagerDemoState extends State<StateManagerDemo> {
int _count = 0;
void countCallBack(){
setState(() {
_count++;
});
debugPrint('$_count');
}
@override
Widget build(BuildContext context) {
//ContentProvider放在最外層,指定參數count和callback
return ContentProvider(
count: _count,
countCallBack: countCallBack,
child: Scaffold(
appBar: AppBar(
title: Text('StateManagerDemo'),
elevation: 0.0,
),
body: Counter1(),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: countCallBack,
),
),
);
}
}
class Counter1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
//直接使用ContentProvider中的參數
final int count = ContentProvider.of(context).count;
final VoidCallback voidCallback = ContentProvider.of(context).countCallBack;
return Center(
child: ActionChip(
label: Text('$count'),
onPressed: voidCallback,
),
);
}
}
複製代碼
首先定義一個數據提供者ContentProvider繼承InheritedWidget,裏面定義咱們須要的count和回調。提供一個of方法讓外界能夠拿到它的實例,方便拿到方法。ide
而後將這個ContentProvider放在主佈局的最外層,並傳入須要的參數count和callBack。這樣它的子部件中就都能訪問到這個參數了。佈局
最後在子部件Counter1中直接使用ContentProvider中的參數。ui
還可使用ScopedModel來完成狀態管理
這是一個第三方的庫,該庫最初是從Fuchsia代碼庫中提取的,使用時須要先導入包,在pubspec.yaml文件中添加依賴
dependencies:
scoped_model: 1.0.1
複製代碼
pub.dev/packages?q=… 這裏能夠看到最新版本。使用這個庫的時候咱們在StatelessWidget中也能夠改變UI
該庫主要分爲三個部分
好比用ScopedModel實現前面的功能
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
class CountModel extends Model{
int _count = 0;
int get count =>_count;
void countIncrease(){
_count ++;
//通知改變
notifyListeners();
}
}
class StateModelDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ScopedModel<CountModel>(
model: CountModel() ,
child: Scaffold(
appBar: AppBar(
title: Text('StateModelDemo'),
),
body: Counter2(),
floatingActionButton: ScopedModelDescendant<CountModel>(
rebuildOnChange: false,
builder: (context, child, model) => FloatingActionButton(
child: Icon(Icons.add),
onPressed: (){
model.countIncrease();
},
),
),
),
);
}
}
class Counter2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ScopedModelDescendant<CountModel>(
builder: (context, child, model) => Center(
child: ActionChip(
label: Text('${model.count}'),
onPressed: (){
model.countIncrease();
},
),
),
);
}
}
複製代碼
Mobx在前端中用的多,且很好用,因此Flutter也引入了,對於咱們Android開發者來講跟學前面幾個的成本都同樣哈哈。
查看版本
github
首先須要去pubspec.yaml文件中引入依賴
dependencies:
mobx: ^0.3.8
flutter_mobx: ^0.3.3
dev_dependencies:
mobx_codegen: ^0.3.9
build_runner: ^1.7.0
複製代碼
而後開始使用mobx完成以前的功能
首先建立一個store類
import 'package:mobx/mobx.dart';
//包含生成的文件
part 'state_manager_demo.g.dart';
class Counter = _Counter3 with _$Counter; abstract class _Counter3 with Store {
@observable
int value = 0;
@action
void increment() {
value++;
}
}
複製代碼
建立完成以後,咱們會發現part後面的內容和_$Counter都會報錯。說是找不到,須要咱們生成。來到AndroidStudio的terminal窗口執行下面命令來生成文件
flutter packages pub run build_runner build
複製代碼
這時候就能夠看到咱們本身的文件state_manager_demo.dart文件旁邊生成了一個新文件state_manager_demo.g.dart,並且不在報錯了。
若是想要修改後.g.dart文件也能自動修改執行
pub run build_runner watch
複製代碼
下面去界面中使用它
class MobxDemo extends StatefulWidget {
@override
_MobxDemoState createState() => _MobxDemoState();
}
class _MobxDemoState extends State<MobxDemo> {
final Counter counter = Counter();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('StateModelDemo'),
),
body: Center(
child: Observer(
builder: (_)=>ActionChip(
label: Text('${counter.value}'),
onPressed: (){
counter.increment();
},
),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed:(){
counter.increment();
},
),
);
}
}
複製代碼
很簡單繼承StatefulWidget,須要監聽的小部件使用Observer包裹起來。而後建立一個成員變量final Counter counter = Counter();
內部就能夠直接使用Counter中的變量和方法了。運行效果跟前面的同樣
谷歌親兒子19年推出的 pub.dev/packages/pr…
添加依賴
provider: 3.1.0+1
複製代碼
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
複製代碼
void main() => runApp(
MultiProvider(child: MyApp(),providers: [
ChangeNotifierProvider(builder: (_) => Counter()),
],)
);
複製代碼
class ProviderDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = Provider.of<Counter>(context);
return Scaffold(
appBar: AppBar(
title: Text('StateModelDemo'),
),
body: ActionChip(
label: Text('${counter._count}'),
onPressed: (){
Provider.of<Counter>(context, listen: false).increment();
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: (){
Provider.of<Counter>(context, listen: false).increment();
},
),
);
}
}
複製代碼
OK 完成
綜合來看這幾種狀態管理的方式 ,我感受Provider是最好用的一個,並且是Google親兒子,後面發展應該也不錯。