每日一题 Flutter#11 | StatelessWidget 从诞生到 build 的流程


最近在着手开发我的 《匠心星问》 ,它定位是一款 题库 应用,将集题目浏览、发布、解答、做题为一体。打算第一步先以 Flutter 为核心,准备题库资源。于是诞生《每日一题》 系列,准备精心设计一些 Flutter 的问题与解答,作为题库的养料。本文的焦点是探讨:

说说 StatelessWidget 从诞生到 build 的流程

在 Flutter 中,build 函数是自定义组件最核心的部分,负责构建和组合 UI 界面。但它的触发是 Flutter 框架内部的行为,理解 build 函数的触发时机,不仅有助于我们更清晰地把握界面构建流程,也能够加深对 Flutter 框架运行逻辑的理解。


1.调试案例

这里以最简单的颜色展示位案例来介绍,如下所示: 自定义一个 ColorView 组件展示颜色,在 MyApp 中构建。我们将专注于 ColorView 从诞生到 build 的流程:

dart 复制代码
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ColorView(color: Colors.blue);
  }
}

class ColorView extends StatelessWidget {
  final Color color;
  const ColorView({super.key, required this.color});

  @override
  Widget build(BuildContext context) {
    return ColoredBox(color: color);
  }
}

想要知道 ColorView#build 的触发时机,只要在断点调试一下就行了。如下,可以看到 build 函数触发时的方法栈调用信息。从这里就可以分析出该方法是如何被 Flutter 框架触发的。


2. StatelessElement 与 build 的渊源

从方法栈中可以看出,ColorView#build 是被 StatelessElement#build 调用的。点击进入可以看到:

  • 这里可以通过 widget 成员拿到 ColorView 对象;
  • Widget#build 中回调的 BuildContext 参数,就是这里的 StatelessElement 对象。

3. 从 mount 开始的新生命

当继续检阅下方的方法栈,同时观察 this 对象。其中 buildperformRebuildrebuild_firstBuildmount 四个函数的 this 指向的都是 持有 ColorView 的 StatelessElement 对象。

直到 Element.inflateWidget 时 this 变成了 MyApp 对应的元素,这块代码中有着丰富的信息:

  • 在这里 newWidget 是 ColorView 组件,通过函数参数传入:
  • 在这里 newWidget 触发了 createElement 方法,创建了 newChild 元素对象。
  • newChild 元素创建完成后,执行 mount ,从而触发 build 工作流。

从这里不难看出 Element.inflateWidget 对应的对象,是父级元素节点。通过该方法得到子级元素节点进行更新。


4. 父节点更新子节点

再往下看一帧,inflateWidget 是由 updateChild 触发的,该方法返回 Element 对象。并且 newWidget 也是入参传递过来的:


再往下,来到了 ElementperformRebuild 方法:

  • 从 5715 行可以看到,上面 newWidget 的来源于 build() 函数。
  • 从 5738 行可以看到,上面 inflateWidget 返回的子元素,将作为当前元素的子节点:

当前的 Element 对象是 MyApp 组件对应的 StatelessElement, 它的 build 方法使用的是对应 Widget的 build:

也就是说,会触发 MyApp#build 返回 ColorView 对象。这就是 ColorView 组件诞生的时机:


5. 总结

到这里,从头到尾梳理一下,StatelessWidget 从诞生到 build 的完整流程。初次的构建流程发生在,父元素节点更新子节点时,会触发 build 方法得到组件,然后通过 inflateWidget 创建子元素节点,并触发子元素 mount 方法。在挂载期间触发首次的构建流程,最终触发对应组件的 build 回调。

sh 复制代码
Element.performRebuild   # 父元素节点更新子节点
    Element.build   # 组件对象诞生
    Element.inflateWidget   # 生成子元素节点
        Widget.createElement()   # 创建子元素节点
        Element.mount()   # 创建子元素节点开始装在
          [Stateless]Element._firstBuild -> rebuild -> performRebuild -> build  # 触发元素构建流
             [Stateless]Element.build  # 触发组件构建

如果你有其他的看法,或者有什么想要的题目、或者想提供题目和答案,都欢迎在评论区留言。更多文章和视频知识资讯,大家可以关注我的公众号、掘金和 B 站 。

相关推荐
围巾哥萧尘30 分钟前
Anthropic Claude for Chrome🧣
面试
要记得喝水2 小时前
C#某公司面试题(含题目和解析)--1
开发语言·windows·面试·c#·.net
岁忧2 小时前
(LeetCode 面试经典 150 题) 200. 岛屿数量(深度优先搜索dfs || 广度优先搜索bfs)
java·c++·leetcode·面试·go·深度优先
没有了遇见3 小时前
Android 原生定位(替代高德 / 百度等三方定位)<终极版本>
android
2501_916008894 小时前
iOS 抓包工具有哪些?全面盘点主流工具与功能对比分析
android·ios·小程序·https·uni-app·iphone·webview
2501_915921434 小时前
iOS混淆工具实战 视频流媒体类 App 的版权与播放安全保护
android·ios·小程序·https·uni-app·iphone·webview
wifi歪f4 小时前
📦 qiankun微前端接入实战
前端·javascript·面试
CYRUS_STUDIO4 小时前
LLVM 全面解析:NDK 为什么离不开它?如何亲手编译调试 clang
android·编译器·llvm
CYRUS_STUDIO4 小时前
静态分析神器 + 动态调试利器:IDA Pro × Frida 混合调试实战
android·逆向
绝无仅有5 小时前
未来教育行业的 Go 服务开发解决方案与实践
后端·面试·github