provider是Google I/O 2019大會宣佈的如今官方推薦的狀態管理方式, provider,語法糖是InheritedWidget,它容許在小部件樹中傳遞數據,容許咱們更加靈活地處理數據類型和數據。vue
flutter_provider 本教程的項目源碼,歡迎stargit
在進行項目的開發時,咱們每每須要管理不一樣頁面之間的數據共享,在頁面功能複雜,狀態達到幾十個上百個的時候,咱們會難以清楚的維護咱們的數據狀態,本文將以簡單計數器功能使用狀態管理來說解如何在Flutter中使用provider這個狀態管理框架github
上次爲你們介紹了provide,而後provide就被棄用了,不過要從provide轉provider學習成本也不高,要了解provide能夠轉Flutter UI使用Provide實現主題切換vuex
使用Provider訪問數據有兩種方式bash
flutter-provider, 可參考項目中使用provider方法app
查看 pub-install框架
dependencies:
provider: 3.0.0+1 #數據管理層
複製代碼
flutter packages get
複製代碼
import 'package:provider/provider.dart'
複製代碼
新建 lib/store/object/CounterInfo.dart 文件less
新建 lib/store/object/UserInfo.dart 文件ide
數據模型,就不貼出代碼了post
新建 lib/store/model/CounterModel.dart 文件
import 'package:flutter/foundation.dart' show ChangeNotifier;
import '../object/CounterInfo.dart';
export '../object/CounterInfo.dart';
class Counter extends CounterInfo with ChangeNotifier {
CounterInfo _counterInfo = CounterInfo(count: 0, totalInfo: TotalInfo(total: 2));
int get count => _counterInfo.count;
TotalInfo get totalInfo => _counterInfo.totalInfo;
void increment () {
_counterInfo.count++;
notifyListeners();
}
void decrement () {
_counterInfo.count--;
notifyListeners();
}
}
複製代碼
新建 lib/store/model/UserModelModel.dart 文件
import 'package:flutter/foundation.dart' show ChangeNotifier;
import '../object/UserInfo.dart';
export '../object/UserInfo.dart';
class UserModel extends UserInfo with ChangeNotifier {
UserInfo _userInfo = UserInfo(name: '咕嚕貓不吃貓糧不吃魚');
String get name => _userInfo.name;
void setName (name) {
_userInfo.name = name;
notifyListeners();
}
}
複製代碼
經過mixin混入ChangeNotifier,經過notifyListeners通知聽衆刷新
新建 lib/store/index.dart 文件
import 'package:flutter/material.dart' show BuildContext;
import 'package:provider/provider.dart'
show ChangeNotifierProvider, MultiProvider, Consumer, Provider;
import 'model/index.dart' show Counter, UserModel;
export 'model/index.dart';
export 'package:provider/provider.dart';
class Store {
static BuildContext context;
static BuildContext widgetCtx;
// 咱們將會在main.dart中runAPP實例化init
static init({context, child}) {
return MultiProvider(
providers: [
ChangeNotifierProvider(builder: (_) => Counter()),
ChangeNotifierProvider(builder: (_) => UserModel(),)
],
child: child,
);
}
// 經過Provider.value<T>(context)獲取狀態數據
static T value<T>(context) {
return Provider.of(context);
}
// 經過Consumer獲取狀態數據
static Consumer connect<T>({builder, child}) {
return Consumer<T>(builder: builder, child: child);
}
}
複製代碼
須要管理多個狀態只須要在providers添加對應的狀態
providers: [ ChangeNotifierProvider(builder: () => Counter()), ChangeNotifierProvider(builder: () => UserModel(),) ],
lib/main.dart 文件
import 'package:flutter/material.dart';
import 'package:flutter_provider/store/index.dart' show Store;
import 'package:flutter_provider/page/firstPage.dart' show FirstPage;
void main () {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('根部重建: $context');
return Store.init(
context: context,
child: MaterialApp(
title: 'Provider',
home: Builder(
builder: (context) {
Store.widgetCtx = context;
print('widgetCtx: $context');
return FirstPage();
},
),
)
);
}
}
複製代碼
新建 lib/page/firstPage.dart 文件
import 'package:flutter/material.dart';
import 'package:flutter_provider/store/index.dart' show Store, Counter, UserModel;
import 'package:flutter_provider/page/secondPage.dart' show SecondPage;
class FirstPage extends StatelessWidget {
TextEditingController controller = TextEditingController();
@override
Widget build(BuildContext context) {
print('first page rebuild');
return Scaffold(
appBar: AppBar(title: Text('FirstPage'),),
body: Center(
child: Column(
children: <Widget>[
Store.connect<Counter>(
builder: (context, snapshot, child) {
return RaisedButton(
child: Text('+'),
onPressed: () {
snapshot.increment();
},
);
}
),
Store.connect<Counter>(
builder: (context, snapshot, child) {
print('first page counter widget rebuild');
return Text(
'${snapshot.count}'
);
}
),
Store.connect<Counter>(
builder: (context, snapshot, child) {
return RaisedButton(
child: Text('-'),
onPressed: () {
snapshot.decrement();
},
);
}
),
Store.connect<UserModel>(
builder: (context, snapshot, child) {
print('first page name Widget rebuild');
return Text(
'${Store.value<UserModel>(context).name}'
);
}
),
TextField(
controller: controller,
),
Store.connect<UserModel>(
builder: (context, snapshot, child) {
return RaisedButton(
child: Text('change name'),
onPressed: () {
snapshot.setName(controller.text);
},
);
}
)
],
),
),
floatingActionButton: FloatingActionButton(
child: Center(
child: Icon(Icons.group_work)
),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (BuildContext context) {
return SecondPage();
}));
// Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) {
// return SecondPage();
// }));
},
),
);
}
}
複製代碼
新建 lib/page/secondPage.dart 文件
import 'package:flutter/material.dart';
import 'package:flutter_provider/store/index.dart' show Store, Counter, UserModel;
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('second page rebuild');
return Scaffold(
appBar: AppBar(title: Text('SecondPage'),),
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
child: Text('+'),
onPressed: () {
Store.value<Counter>(context).increment();
},
),
Builder(
builder: (context) {
print('second page counter widget rebuild');
return Text(
'second page: ${Store.value<Counter>(context).count}'
);
},
),
RaisedButton(
child: Text('-'),
onPressed: () {
Store.value<Counter>(context).decrement();
},
),
],
),
),
);
}
}
複製代碼
細心的同窗能夠發現我在firstPage中使用獲取數據狀態所有都是經過Consumer來獲取的,在firstPage中使用了兩個store(Counter和UserModel)綁定了兩個不一樣的weiget,好處就在於:
結果是first page rebuild只會在頁面初始化的時候進行打印,而操做數據增減和name修改只會從新渲染對應的weiget,下圖分別爲單獨進行一次數據修改和name修改後的控制檯輸出
結果是second page rebuild會在頁面初始化的時候進行打印,但每次數據修改時一樣也會進行print
綜上,使用Provider.value(context)會致使頁面刷新,雖然flutter會自動優化刷新,但仍是建議你們儘可能使用Consumer去獲取數據,能夠獲取最好app的性能提高
歡迎更多學習flutter的小夥伴加入QQ羣 Flutter UI: 798874340
敬請關注咱們正在開發的:efoxTeam/flutter-ui