Flutter最小刷新范围探索ValueListenableBuilder使用详解
WeninerIo 人气:0引子
管理对象太多?
刷新管理太麻烦 ?
Flutter刷新范围控制不好 ?
不妨看看本文 , 希望提供给你一些思路吧 !
说起 Flutter 刷新, 你的第一印象是什么 ? setState ? 是的, 只要使用过 Flutter 的人, 第一印象都必然是 setState , 但是由于 setState 滥用的问题, 性能问题就脱颖而出.
因此产出了诸如 Fish_redux 之流, 这些框架尽可能的使用 StatelessWidget 而由框架本身来引导刷新. 那么, 我们除了框架, 有没有办法来控制 Flutter 的刷新呢?
ValueListenableBuilder
ValueListenableBuilder 是基于 Flutter 自身特点构建的一个 widget. 它借助了观察者模式 , 高效率的引导 Flutter 框架来刷新指定位置. 在繁杂的界面中, 细粒化的更新特定的 widget. 我们接下来, 举例子并分析一下它是如何用,怎么做的吧!
如何用
这里我们通过一个简单的例子 - 计数器, 它的作用是每点击一次按钮, 数字便会增加一.
Scaffold( body: Center( child: Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text(num.toString()), IconButton( color: Colors.blue, onPressed: () { if (mounted) { setState(() { num++; }); } }, icon: const Icon(Icons.add), ), ], ), ), )
我们打开Android studio 自带的工具 Flutter Performance , 打开 Track widget rebuilds. 记录下点击十次后, 整体界面的刷新次数.
结果上, 我们发现了整体页面的每个组件都刷新了十次. 我们再通过 ValueListenableBuilder 来重构页面, 并同样刷新十次
final ValueNotifier<int> notifier = ValueNotifier(0); Scaffold{ body: Column{ ... children: [ ValueListenableBuilder<int>( valueListenable: notifier, builder: (BuildContext context, value, Widget? child) { return Text( value.toString(), style: const TextStyle(fontSize: 20), ); }, ), ... ] } }
这次我们可以看到,除了 ValueListenableBuilder 和 Text 本身刷新了十次, 其余的 widget没有再刷新. 因此, 我们可以推断出层级越深、组件越多, 我们优化的效果也就越明显
那么, 这是怎么做到的呢 ? 让我们来一起探究一下 .
怎么做
ValueListenableBuilder 是一个 StatefulWidget. 也就是说它具备刷新的能力, 它通过监听 ValueListenable 对象的变换.我们将目光转到它的 State 中. 在 initState 中 , 也就是最初加载这个 widget 的时候. 我们初始化了 value 的值, 并且增加了一个监听.
@override void initState() { super.initState(); value = widget.valueListenable.value; widget.valueListenable.addListener(_valueChanged); }
在这个监听中, 我们发现只要 valueListenable 的值发生变化, 便会立即通知当前 state 刷新. 因此它的刷新范围只限制于局部.
void _valueChanged() { setState(() { value = widget.valueListenable.value; }); }
同时, 它在外部可能刷新修改 valueListenable 对象的时候, 移除了之前的监听. 并增加了新的监听对象. 其余的步骤还是和之前一样.
@override void didUpdateWidget(ValueListenableBuilder<T> oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.valueListenable != widget.valueListenable) { oldWidget.valueListenable.removeListener(_valueChanged); value = widget.valueListenable.value; widget.valueListenable.addListener(_valueChanged); } }
通过这一系列的操作, Flutter 实现了点对点的刷新方案.
不足点
虽然 ValueListenableBuilder 已经解决了大部分刷新场景需要定向刷新的需求, 但是它刷新的颗粒度还不够. 如果我们针对每个 widget 都需要不同的对象通知更新, 那么, 我们就要自己手动创建 N 个通知者, 这给开发带来了难以预料的维护难度. 因此, 在实际运用的场景中, 我们更偏向于单个不与其他业务接触的业务或者一个自行维护的widget. 尽可能减少业务复杂度. 为了解决这种问题, Getx、Bloc、Provider都算比较好的状态管理框架.
加载全部内容