跨平台框架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组件————FloatingActionButton
前端·flutter·dart
coder_pig7 小时前
📝小记:Ubuntu 部署 Jenkins 打包 Flutter APK
flutter·ubuntu·jenkins
捡芝麻丢西瓜9 小时前
flutter自学笔记5- dart 编码规范
flutter·dart
恋猫de小郭9 小时前
什么?Flutter 可能会被 SwiftUI/ArkUI 化?全新的 Flutter Roadmap
flutter·ios·swiftui
sunly_1 天前
Flutter:导航,tab切换,顶部固定,列表分页滚动
开发语言·javascript·flutter
敲代码的小强2 天前
Flutter项目兼容鸿蒙Next系统
flutter·华为·harmonyos
Zh-jie2 天前
flutter 快速实现侧边栏
前端·javascript·flutter
truemi.733 天前
flutter --no-color pub get 超时解决方法
android·flutter
王家视频教程图书馆3 天前
flutter 使用dio 请求go语言后台数据接口展示瀑布流图片
flutter
迷雾漫步者3 天前
Flutter组件————AppBar
flutter·跨平台·dart