跨平台框架Flutter工作原理初探

前言

Flutter是开发跨平台应用的框架,支持将应用打包到几乎市面所有平台,本文较浅层次探究flutter框架的工作原理

参考来源为flutter中文社区官方文档

Flutter 开发文档 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter

flutter的布局

组合性

widget是组合其他简单而基础的widget的方式构建的,这也是flutter官方编写官方widget的理念,一个很鲜明的例子就是padding是widget而不是widget属性

RenderObjectWidget

这是widget递归构建的底层,用于在渲染树(存储用户界面几何信息的数据结构)构建子节点,flutter开发者无需创建这些对象,而是使用widget来操纵渲染树

保持widget渲染高性能的关键

次线性布局

Flutter对每一帧执行一次布局操作,约束信息通过父节点调用子节点布局方法向下传递,子节点递归执行自己的布局操作,并将几何信息返回添加到渲染树

一旦渲染对象从布局中返回,该对象将不会被再次访问,直到下一帧布局

布局期间,从父节点流向子节点的唯一信息是约束信息,从子节点流向父节点的唯一信息是几何信息

  • 每个 Widget 接收来自其父 Widget 的约束(如最大/最小宽度和高度),然后确定自己的大小。
  • 父 Widget 会根据子 Widget 的大小和其他因素(如布局规则)来决定子 Widget 的位置。
  • 如果子 Widget 在连续的布局过程中接收到相同的约束,并且没有标记为需要重建(脏),则可以快速完成布局,无需重新计算。
  • 父 Widget 可以根据子 Widget 的大小信息进行布局,但在某些情况下,即使子 Widget 的大小发生变化,父 Widget 也不需要重新布局。
  • 在某些情况下,如果父 Widget 对子 Widget 施加了严格的约束,子 Widget 的大小变化不会迫使父 Widget 重新布局。

次线性widget构建

Widget、Element 和 State

Widget:是不可变的,定义了 UI 的结构和配置

Element:是 Widget 的实例化,形成了一个树结构(Element 树),用来管理 Widget 的布局和状态。它们是可变的,并能够记住 Widget 的父子关系

State:与 Stateful Widgets 相关联的对象,用于保存可变数据

次线性 Widget 构建

当状态改变,相关的 Element 会被标记为 "脏"(需要重新构建)

Flutter 维护了一个脏 Element 的列表。在构建过程中,只有标记为脏的 Element 会被重新构建,而不是整个树

单向数据流和清洗机制

数据在 Element 树中单向向下传递,每个 Element 在一个构建周期中最多被访问一次

一旦 Element 被更新(清洗),在当前构建周期内它不会再被标记为脏,因为它和它的所有祖先都已经是最新的

Widget 的不可变性和重用

由于 Widgets 是不可变的,如果父 Widget 重建了,但相关的 Element 没有变脏,则该 Element 可以直接重用,无需重新构建

Element 可以通过比较 Widget 的身份(而非其属性)来快速检查是否需要更新

InheritedWidgets 的使用

为了避免在构建过程中频繁遍历父链(例如,查找主题颜色等),Flutter 使用 InheritedWidgets在 Element 上维护一个哈希表来高效地向下传递信息,避免了深度遍历的高成本

线性协调

  • Flutter 不使用传统的树差异比较算法,而是通过一个 O(N) 算法来独立检查每个 element 的子节点,以确定是否可以重用该 element
  • 子列表协调算法优化了几种情况:空的旧子列表、完全相同的新旧列表、列表中某位置的插入或删除操作,以及含有相同 key 的 widget 的识别

树结构优化

  • Element 的重用对性能至关重要,因为 element 保存着 Stateful widget 的状态对象和底层的渲染对象
  • 全局树更新(通过 GlobalKey 实现)允许将 widget 在 element 树中移动而不重新构建它们,从而保留状态和布局信息
  • 当 element 被重用时,其相关的渲染对象可以保留布局信息,减少了不必要的布局计算

恒定因子优化

  • Flutter 的渲染树不依赖于具体的子模型,这提高了布局方法的效率
  • 视觉渲染树和 widget 的逻辑树是分开的,以提高布局和绘制计算的效率
  • 文本由专门的渲染对象(RenderParagraph)处理,避免了文本布局的重复计算
  • Flutter 使用观察者模式,其中可观察对象(如 Animation)在值变化时通知观察者,允许渲染树仅在必要时进行重绘,而不是完全重建和重绘

Element 树和 RenderObject 树的分离

  • Flutter 中的 RenderObject 树(负责渲染)和 Element 树(基于 Widget 的逻辑结构)是分开的,尽管它们在结构上有所同构
  • 这种分离带来了多个好处,包括性能优化(只遍历布局相关的树)、清晰的 API 设计(分离职责),以及类型安全(运行时确保子节点类型的合适性)

无限滚动

  • Flutter 支持无限滚动列表,这是通过构造器模式实现的,其中 ListView 按需构建 widget

视窗感知布局

  • 可滚动的 widget 由一个外部的 Viewport 组成,它定义了一个比实际屏幕更大的内部空间
  • Viewport 的子节点不是普通的 RenderBox,而是实现了视窗感知协议的 RenderSliver
  • Sliver 布局协议中的约束和几何数据结构与传统的盒子布局不同,它们更关注于视窗口内的可见空间和滚动效果
相关推荐
旭日猎鹰2 小时前
Flutter踩坑记录(三)-- 更改入口执行文件
flutter
旭日猎鹰2 小时前
Flutter踩坑记录(一)debug运行生成的项目,不能手动点击运行
flutter
️ 邪神2 小时前
【Android、IOS、Flutter、鸿蒙、ReactNative 】自定义View
flutter·ios·鸿蒙·reactnative·anroid
比格丽巴格丽抱14 小时前
flutter项目苹果编译运行打包上线
flutter·ios
SoaringHeart14 小时前
Flutter进阶:基于 MLKit 的 OCR 文字识别
前端·flutter
AiFlutter19 小时前
Flutter通过 Coap发送组播
flutter
嘟嘟叽2 天前
初学 flutter 环境变量配置
flutter
iFlyCai2 天前
深入理解Flutter生命周期函数之StatefulWidget(一)
flutter·生命周期·dart·statefulwidget
sunly_2 天前
Flutter:photo_view图片预览功能
android·javascript·flutter
Summer不秃2 天前
Flutter中sqflite的使用案例
flutter