一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情。
测试描述
可能很多人会认为,每次的 State#setState
都会触发当前状态类的 build
方法重新构建。但真的是这样吗,你真的了解 Flutter
界面的更新流程吗?
本篇文章将做一个极限测试
,看一下连续触发 1000000
次 setState
会发生什么?是连续触发 1000000
次屏幕更新,导致界面卡死,还是无事发生?用你的眼睛来见证吧!
另外,本文有对应的视频版,可在 哔哩哔哩
进行观看:
【Flutter极限测试 - 连续 setState 1000000 次会怎么样? 】
1、测试代码说明
如下所示,在默认案例基础上添加了两个蓝色文字,点击时分别触发如下的 _increment1
和 _setState1000000
。其中 _setState1000000
是遍历执行 1000000
次 setState
。
dart 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
次,并无大事发生的原因。
本文就到这里,以后有什么稀奇古怪的测试,还会通过文件 + 视频的方式分享,下次再会 ~