【 Flutter 极限测试】连续 1000000 次 setState 会怎么样

2,375 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情


测试描述

可能很多人会认为,每次的 State#setState 都会触发当前状态类的 build 方法重新构建。但真的是这样吗,你真的了解 Flutter 界面的更新流程吗?

本篇文章将做一个极限测试,看一下连续触发 1000000setState 会发生什么?是连续触发 1000000 次屏幕更新,导致界面卡死,还是无事发生?用你的眼睛来见证吧!

另外,本文有对应的视频版,可在 哔哩哔哩 进行观看:

Flutter极限测试 - 连续 setState 1000000 次会怎么样?


1、测试代码说明

如下所示,在默认案例基础上添加了两个蓝色文字,点击时分别触发如下的 _increment1_setState1000000 。其中 _setState1000000 是遍历执行 1000000setState

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 时,则直接返回,不会执行接下来的方法。如果 dirtyfalse ,那接下来会置为 true

另外,owner.scheduleBuildFor 用于收集脏元素,以及申请新帧的触发。这就是为什么连续执行 1000000stateState 时,该元素不会加入脏表 1000000 次,不会触发 1000000 帧的原因。

总的来说, State#setState 的核心作用就是把持有的元素标脏申请新帧调度。而只有新帧到来,执行完构建之后,元素的 dirty 才会置为 false 。也就是说,两帧之间,无论调用多少次 setState ,都只会触发一次, 元素标脏申请新帧调度 。这就是为什么连续触发 1000000 次,并无大事发生的原因。


本文就到这里,以后有什么稀奇古怪的测试,还会通过文件 + 视频的方式分享,下次再会 ~