1. 什么是flutter
Flutter 是 Google 开源的 UI 工具包,帮助开发者通过一套代码库,
高效构建多平台精美应用,支持移动、Web、桌面和嵌入式平台。
1.1 flutter 优势
- Flutter 很好的解决了跨端一致性问题,一套代码无差异的同时跑在 iOS 与 Android 两端;
- 开发体验基本接近前端.
- 支持
on device
的Hot Reload
, - Flutter 在 Android Studio 中通过插件实现实时预览并支持交互的
Hot UI
能力,以及Layout Explorer
可视化布局,让Flutter 的开发效率和前端效率基本持平。
2. FLutter 架构
Flutter的整体架构共分为三层,从下到上分别为:Embedder层
、Engine层
、Framework层
。
分别对应:
- Framework层:用Dart实现的上层UI SDK。
- Engine层:渲染引擎层。
- Embedder层:操作系统底层适配层。
-
Framework
层:Dart实现的上层UI SDK 实现了:Animation(动画
)、Painting(图形绘制)
、Gestures(手势操作)
等功能,并包装成对应的 api 提供给上层开发者调用。为了保证Flutter所绘制的控件与原生控件风格类似,Flutter封装了Material
(对应Android)、Cupertino
(对应iOS)风格的UI组件库,供开发者直接使用。 -
Engine
层:Skia渲染 + DartVM 引擎
这层主要包含三块:Skia、Dart、Text。- Skia 是渲染引擎,为 Framework 层提供“底层渲染”能力。
- Dart 是 Dart 运行时引擎,为 Framework 层提供运行时调用Dart和渲染能力。
- Text 是文字排版,为 Framework 层提供视图排版能力。
-
Embedder
层:操作系统适配
对不同平台操作系统的适配,包括一些配置:surface、线程、插件等特性。 由于Flutter相关特性并不多,因此对不同平台操作系统的适配成本很低。
3.执行流程
从结构上看,Flutter渲染由UI Thread与GPU Thread相互配合完成。
1)UI Thread
对应图中1-5,执行Dart VM中的Dart代码(包含应用程序和Flutter框架代码),主要负责Widget Tree、Element Tree、RenderObject Tree的构建,布局、以及绘制生成绘制指令,生成Layer Tree(保存绘制指令)等工作。
2)GPU Thread
对应图中6-7,执行Flutter引擎中图形相关代码(Skia),这个线程通过与GPU通信,获取Layer Tree并执行栅格化以及合成上屏等操作,将Layer Tree显示在屏幕上。
1
2
注:图层树(Layer Tree)是Flutter组织绘制指令的方式,
类似于Android Rendering里的View DisplayList,都是组织绘制指令的一种方式。
UI Thread与GPU Thread属于生产者和消费者的角色。
Flutter 渲染工作流水线
渲染原理解释了 flutter 是如何跨平台的
渲染过程,UI线程完成布局、绘制操作,生成Layer Tree; GPU线程执行合成并光栅化后交给GPU来处理,其中几个关键步骤:
- Animate: 遍历_transientCallbacks,执行动画回调方法;
- Build: 对于dirty的元素会执行build构造,没有dirty元素则不会执行,对应于buildScope()
- Layout: 计算渲染对象的大小和位置,对应于flushLayout(),这个过程可能会嵌套再调用build操作;
- Compositing bits: 更新具有脏合成位的任何渲染对象, 对应于flushCompositingBits();
- Paint: 将绘制命令记录到Layer, 对应于flushPaint();
- Compositing: 将Compositing bits发送给GPU, 对应于compositeFrame();
GPU线程通过skia向GPU硬件绘制一帧的数据,GPU将帧信息保存到FrameBuffer里面, 然后视频控制器会根据VSync信号,从FrameBuffer取帧数据传递给显示器,从而显示出最终的画面。(Vulkan,OpenGL,Metal)
4.渲染策略
在Flutter中,Everything is widget。所有 Widget 会组成 Widget Tree 。
界面更新时,会更新 Widget Tree ,再更新 Element Tree ,最后更新 RenderObjectTree 。
分为4个阶段,分别是:
1
2
布局阶段 => 绘制阶段 => 合成阶段 => 渲染阶段
(Layout => Paint => Composite => Rasterize)
- 布局(Layout)
Flutter采用 “深度优先” 机制遍历Widget Tree。 为了防止孩子节点的变化,导致整个 Widget Tree 重新布局。 Flutter加入了 “布局边界” 机制(Relayout Boundary) 布局完成后,树上每个节点都确定了“尺寸大小”和“位置”。
- 绘制(Paint)
布局完成后,确定了树上的控件的“尺寸”与“位置”。 接下来是绘制阶段。
和布局类似,Flutter也是采用 “深度优先” 机制遍历渲染树。 先绘制自身,再绘制子节点。 为了解决绘制覆盖问题,Flutter采用了也是和布局阶段相似的策略: 重绘边界 机制(Repaint Boundary)。 其实,本质上就是加个新的图层,避免在同一图层重绘产生影响。 典型的例子是,ScrollView。 一旦设置好重绘边界,滚动时,只会重绘ScollView中的视图内容,而其他部分不用重新绘制。
-
合成(Composite) 由于绘制出来的渲染树,会有很多层,同步多层渲染会出现性能问题。
因此,Flutter会在渲染前,将多个渲染树图层进行合成。
根据多层渲染树的大小、层级、透明度等计算后,
合成为最终“简化版”的渲染树,以提高下一步的渲染效率。 -
渲染(Rasterize) 将处理过的“简化版”渲染树,交给Skia引擎转换成“二维图像数据”。
然后 Skia 把计算好的图形数据,通过 OpenGL 接口交给 GPU 渲染,走 GPU 工作流水线:
顶点着色器 => 形状装配 => 几何着色器 => 光栅化 => 片段着色器 => 测试与混合
。
然后,GPU工作流水线六阶段完成。最终,展示到终端屏幕上。
当然这只是一个垂直同步信号(VSync)的过程。(按60fps算,一秒需要60个VSync才不会感到卡顿。)
5.工程实例讲解
5.1.常用组件
5.2特性展示
- 4.1 hotReload
- 4.2 Android/iOS style
参考资料
Flutter Samples
了解Flutter渲染机制
iOS 浅谈GPU及“App渲染流程”
Flutter 究竟是如何渲染的
Flutter渲染机制—GPU线程
谈一谈Flutter外接纹理
Flutter初始化流程
深入了解Flutter界面开发
深入理解flutter的编译原理与优化
深入理解Flutter Platform Channel
Flutter快速上车之Widget
Flutter 工作原理
Flutter 中文文档
Flutter 架构概览
Flutter 文档
Dart