一、什么是provider
Provider是谷哥用来替换之前的状态管理 Provide,虽然只有一个字母之差使用方式差别却很大。Flutter 针对不同类型对象提供了多种不同的 Provider;Provider 也是借助了 InheritWidget,将共享状态放到顶层 MaterialApp 之上。
Provider 能提供你:
- 简化资源分配/处置
- 延迟加载
- 每次都制作新类时大大减少了样板
- devtools友好
- 使用这些InheritedWidget的常用方法(请参阅Provider.of / Consumer / Selector)
- 侦听机制的复杂度呈指数增长,从而提高了类的可伸缩性(例如ChangeNotifier,它是用于调度通知的复杂度O(N²))
二、Provider组件的使用
因为项目里使用的是 provider: ^4.0.4,所以以这个版本的为主。
现在到了 5.0.0 ,大概看了一下更新优化了不少,有兴趣的可以去看看。
Consumer的基本用法
新建一个数据提供类,这个类主要是用来提供数据
class DataProvider extends ChangeNotifier{
int count=0;
int count1=0;
void add(){
count++;
print("count:$count");
notifyListeners();
}
void add1(){
count1++;
print("count1:$count1");
notifyListeners();
}
}
```bash
return ChangeNotifierProvider(
create: (_) => DataProvider(),
child: Column(
children: <Widget>[
Consumer<DataProvider>(builder: (_, data, __) {
print("text1 rebuild");
return Text(data.count.toString());
}),
Consumer<DataProvider>(builder: (_, data, __) {
print("text2 rebuild");
return Text(data.count1.toString());
}),
Consumer<DataProvider>(
builder: (_, data, __) => GestureDetector(
onTap: () {
data.add();
},
child: Container(
margin: EdgeInsets.all(30),
decoration: BoxDecoration(border: Border.all(color: Colors.red)),
child: Text("我增加了count"),
),
),
),
Consumer<DataProvider>(
builder: (_, data, __) => GestureDetector(
onTap: () {
data.add();
},
child: Container(
margin: EdgeInsets.all(30),
decoration: BoxDecoration(border: Border.all(color: Colors.red)),
child: Text("我增加了count1"),
),
),
),
],
),
);
运行结果:
I/flutter (24104): count:1
I/flutter (24104): text1 rebuild
I/flutter (24104): text2 rebuild
Consumer的其他写法
class ChildAWidget extends StatelessWidget {
final Widget child;
final dynamic data;
ChildAWidget({this.child, this.data});
@override
Widget build(BuildContext context) {
print("ChildAWidget build");
return Container(
child: Column(
children: <Widget>[Text("$data" ?? "ChildAWidget"), child],
),
);
}
}
class ChildBWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("ChildBWidget build");
return GestureDetector(
onTap: () {
Provider.of<DataProvider>(context).add();
},
child: Container(
child: Text("点我啊"),
),
);
}
}
return ChangeNotifierProvider(
create: (_) => DataProvider(),
child: Consumer<DataProvider>(
builder: (_, data, child) => ChildAWidget(
child: child,
data: data.count,
),
child: ChildBWidget(),
),
);
这个例子中, ChildBWidget是在 builder 之外进行重绘的。然后 ChildAWidget实例作为最一个参数传递给给 builder 。
这意味着 builder 会被反复调用时, Consumer 并不会创建 ChildBWidget新实例。这会让 Flutter 知道不必重新绘制 ChildBWidget。所以通过这么样的一个写法,当 DataProvider有更新时,只有 ChildAWidget才会进行重绘。
selector基本用法
return ChangeNotifierProvider(
create: (_) => DataProvider(),
child: Column(
children: <Widget>[
Selector<DataProvider, int>(selector: (_, store) => store.count, builder: (_, data, __){
{
print("text1 rebuild");
return Text(data.toString());
}
}),
Selector<DataProvider, int>(selector: (_, store) => store.count1, builder: (_, data, __){
{
print("text2 rebuild");
return Text(data.toString());
}
}),
Consumer<DataProvider>(
builder: (_, data, __) => GestureDetector(
onTap: () {
data.add();
},
child: Container(
margin: EdgeInsets.all(30),
decoration: BoxDecoration(border: Border.all(color: Colors.red)),
child: Text("我增加了count"),
),
),
),
Consumer<DataProvider>(
builder: (_, data, __) => GestureDetector(
onTap: () {
data.add1();
},
child: Container(
margin: EdgeInsets.all(30),
decoration: BoxDecoration(border: Border.all(color: Colors.red)),
child: Text("我增加了count1"),
),
),
),
],
),
);
运行结果:
I/flutter (24104): count:1
I/flutter (24104): text1 rebuild
selector其他写法
return ChangeNotifierProvider(
create: (_) => DataProvider(),
child: Selector<DataProvider, int>(
builder: (_, d, child) => ChildAWidget(
child: child,
data: d,
),
shouldRebuild: (pre,next)=>pre!=next,
selector: (BuildContext c, DataProvider d) {
return d.count;
},
child: ChildBWidget(),
),
);
如果想使用多个provider的话,可以使用MultiProvider。
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: DataProvider()),
ChangeNotifierProvider.value(value: DataProvider1()),
],
child: ChildCWidget(),
);
三、总结
其实consumer和selector用法上没多大区别,有点区别的是,consumer只要是值改变了都会通知它的宿主刷新UI,而selector能够选取部分值更新。Selector控制的粒度比Consumer更细,Consumer是监听一个Provider中所有数据的变化,Selector则是监听某一个/多个值的变化。从上面的运行结果就可以看出来。
还有一些provider的组件没介绍,我基本是自己在项目上用到才会写。好了,完结撒花,又记录了一个学习的过程。