对于Flutter开发的工程师们,肯定是对Provider很熟悉.
这个是官方推荐的一个状态管理插件.对于 Flutter应用 Provider的出现是提高App性能一剂良药,也是管理状态的良好工具,可是Provider真的就是一个没有副作用的状态管理利器吗? 非也! 甚至他会毁掉你的App!
完全无必要的无脑使用首先我们以一个widgets树为例来解说:
图例说明:
上图中 我们Widgets 分别是一个Root视图;还有 4个 子Widgets, 分别是:
- Text
- Chart1
- Chart2
- ListView
子Widgets 它们分别对应数据源是:
- $text
- $chartData1
- $chartData2
- $list
现在清楚我们的Widgets树层级结构和数据来源,我们开始使用Provider来进行 状态管理 ;首先我们应该在根Widget中设置 ChangeNotifierProvider 用来包裹数据源和组件视图;然后创建ChangeNotifier关联数据和变化通知;最后子视图就可以跨层级使用 ChangeNotifierProvider 包裹的数据源.简单说明一下代码逻辑:我们来看一下例子:
构建一个ChangeNotifier:
```
class ModelNotifier extends ChangeNotifier {
var text;
var chartData1;
var chartData2;
var list;
updateText(newText) {
text = newText ;
notifyListeners();
}
...省略其余更新函数...
// 获取远程数据源
getRemoteData() {}
}
ps: 伪代码
```
这是一个简单的页面级的例子:
```
... 省略非关键代码
return ChangeNotifierProvider(
create: (context) => CartModel(),
child: const RootWidget(
Consumer(Text($text)),
Collection(
Consumer(Chart1($chartData1)),
Consumer(Chart2($chartData2)),
),
Consumer(ListView($list)),
),
)
... 省略非关键代码
ps: 伪代码
```
以上我们将伪代码也粘贴了出来, 现在我们来演示一下数据从远程过来之后,Provider更新数据状态进而更新UI的流程.
首先,假设这是一个接口返回回来的数据,这个时候 我们将 一并获取:$text、$chartData1、$chartData2、$list的数据,那么我们想要更新4个子Widget 就必须分别调用updateText以及其他的更新视图的函数,并传递从接口获取到新的数据;这个时候我们就会发现,Provider的使用就变的没有任何意义,甚至拖沓了更新UI的时间, 我们完全可以不使用Provider 处理数据,完全可以在根视图中采用 setStates 函数来刷新整个层级树,以为此时的Provider做的事情也是刷新整个层级树视图.所以分析可以知道有几个不合理的点:
- 一个接口就获取到所有数据
- 更新数据源的时候没有判断数据的更新内容
改良
我们就针对两个问题进行处理,第一我们分别对接口进行拆分若干:
1. 获取Text 内容
2. 获取 两个 Charts 的内容
3. 获取 ListView 的内容
这样我们可以在获取某些数据的时候对部分组件进行更新,且在同一时间减少了整体渲染带来的大量性能损耗.
其次,对新数据的检查也是有必要的额,首先我们要增加数据新旧检验的机制,在通过检验,新数据符合渲染条件,就通知更新,否则就放弃本次的更新,这样也在一定程度上减少渲染次数.
总结
Provider的合理使用是提高整体性能的保证,我们在很多的静态数据面前,其实是没有使用Provider的必要的,甚至在一些只是更新数据而不涉及UI更新的地方也需要使用注意使用Provider的非更新UI机制用法,其次就是 针对接口的调整,在庞大的数据集合中,合理地拆分接口数据可以减少对流量的浪费.也可以让用户体验更上一个台阶.
,