【 Flutter 极限测试】连续 1000000 次 setState 会怎么样
测试描述
可能很多人会认为,每次的 State#setState 都会触发当前状态类的 build 方法重新构建。但真的是这样吗,你真的了解 Flutter 界面的更新流程吗?
本篇文章将做一个极限测试,看一下连续触发 1000000 次 setState 会发生什么?是连续触发 1000000 次屏幕更新,导致界面卡死,还是无事发生?用你的眼睛来见证吧!
1、测试代码说明
如下所示,在默认案例基础上添加了两个蓝色文字,点击时分别触发如下的 _increment1 和 _setState1000000 。其中 _setState1000000 是遍历执行 1000000 次 setState 。
void _increment1() {
setState(() {
_counter++;
});
}
void _setState1000000() {
for (int i = 0; i < 1000000; i++) {
setState(() {
_counter++;
});
}
}
2、运行结果
如下是在 profile 模式下,网页调试工具中的测试结果。可以看出即使连续触发了 1000000 次的 steState ,也不会有 1000000 次的帧触发来更新界面。也就是说,并非每次的 steState 方法触发时,都会进行重新构建,所以,你真的懂 State#steState 吗?
3. 源码调试分析
如下,在 State#setState 源码中可以看出,它只做了两件事:
触发入参回调 fn 。
执行持有元素的
markNeedsBuild方法。
这里 1121 行的 fn() 做了什么,不用多说了吧。就是 setState 入参的那个自加方法。
此时该 State 中持有的 _element 对象类型是 StatefulEmement ,也就是 MyHomePage 组件创建的元素。
在 Elememt#markNeedsBuild 方法中没有一个非常重要的判断,那就是下面 4440 行 中,如果 dirty 已经是 true 时,则直接返回,不会执行接下来的方法。如果 dirty 是 false ,那接下来会置为 true 。
另外,owner.scheduleBuildFor 用于收集脏元素,以及申请新帧的触发。这就是为什么连续执行 1000000 次 stateState 时,该元素不会加入脏表 1000000 次,不会触发 1000000 帧的原因。
总的来说, State#setState 的核心作用就是把持有的元素标脏并申请新帧调度。而只有新帧到来,执行完构建之后,元素的 dirty 才会置为 false 。也就是说,两帧之间,无论调用多少次 setState ,都只会触发一次, 元素标脏 和 申请新帧调度 。这就是为什么连续触发 1000000 次,并无大事发生的原因。
作者:张风捷特烈
来源:https://juejin.cn/post/7091471603774521352