深入剖析 Flutter 原理:Dart 语言、Flutter 引擎、响应式设计模式、原生渲染
Flutter 是 Google 于 2018 年发布的跨平台移动用户界面界面。与通过 Javascript 开发的 React-Native 不同, Flutter编程语言是Dart,因此不需要Javascript引擎来运行,但实际效果最终是通过原生渲染来呈现的。
由 Google 制作,Dart 语言,Flutter 引擎,响应式设计模式,原生渲染。
图形性能媲美原生应用
其他框架只是OEM封装,Flutter可以直接支持Skia进行绘图。
跨平台:移动、Web、桌面、嵌入式
框架结构
从这个架构图可以看出,Flutter框架可以分为Framework层和Engine层;
框架部分使用了Dart语言,也是本系列文章的主体部分。
引擎部分是用C++实现的。引擎为框架提供支持,也是框架与系统(Android/iOS)之间的桥梁。
Flutter框架:整个框架层都是用Dart语言实现的。该层提供了一套处理动画、绘图、手势等的基础库,并基于绘图封装了一套用户界面组件库,分为两种组件风格。
Basics、Animations、Painting 和 Gestures 是由 Dart 实现的用户界面层,提供动画、手势和绘图。
渲染层依赖于UI层。在运行时,渲染层创建一个小部件树。如果有变化,就会按照一定的算法计算出变化的部分,然后更新widget树。
Widgets层是Flutter提供的一组基础组件库。除了基本的组件库之外,Flutter 还提供了两种视觉风格的组件库:Material 和 Cupertino。材质:Android风格小部件。它被 Google Chrome、Chrome OS、Android、Firefox、Firefox OS 和许多其他浏览器用作图形引擎。
Skia 由 Google 资助,任何人都可以根据 BSD 自由软件许可证使用。 Skia开发团队致力于开发其核心组件,并广泛接受对Skio的开源贡献。
由于它不使用原生UI和绘图框架,因此保证了高性能的Flutter体验。
Flutter Engine:这是一个纯C++实现的SDK,包含了Skia引擎、Dart运行时、文本排版引擎等。但说白了,它是一个Dart运行时,可以JIT、Mode JIT执行Dart代码快照或 AOT。当代码调用 dart:ui 库时,dart:ui 库中提供了本机绑定实现。但不要忘记,这个运行时还处理 VSync 信号的传输、GPU 数据填充等,并且还负责将客户端事件传递给运行时代码。
sdk源码
…/sdk/flutter/packages/flutter/lib
Flutter for web
对比一下,你会发现Web框架层和移动端几乎一模一样。因此,您只需要重新实现引擎和嵌入层,就可以将 UI 代码从 Android/IOS Flutter 应用完全移植到 Web,而无需更改 Flutter API。 Dart可以使用Dart2Js编译器将Dart代码编译为JS代码。大多数原生应用元素都可以通过 DOM 实现,而无法通过 DOM 实现的元素可以通过 Canvas 实现。
通信
得益于Engine层,Flutter甚至不使用移动平台的原生控制。相反,它使用自己的 Engine 来绘制 widget(Flutter 的显示单元),并且 Dart 代码通过 AOT 编译为原生平台组件。代码,因此 Flutter 可以直接与平台通信,而不需要 JS 引擎桥。同时,Flutter 唯一需要系统提供的就是用于实现 UI 绘制的画布。
对于Android平台,Flutter引擎的C/C++代码由NDK编译。 LLVM是在iOS平台上编译的。两个平台的 Dart 代码都是 AOT 编译为本机代码,而 Flutter 使用本机指令。设定操作。 Flutter 使用相同的渲染器、框架和小部件集来同时构建 iOS 和 Android 应用程序,而无需维护两个独立的代码库。
通过平台渠道进行本地沟通。
Native 还可以通过 MethodChannel 调用 Flutter 方法,这是一个双向通道。
关于垂直同步
Android 显示器的运行速度约为 60fps,一帧约为 16.6ms。
如果绘制间隔超过16ms,就会出现卡顿现象。
图形渲染
渲染管道
在Flutter内部,有一个渲染管道(rendering pipeline)。该渲染管线由垂直同步信号(Vsync)驱动,Vsync信号由系统提供。如果您的 Flutter 应用程序在 Android 上运行,则 Vsync 信号就是熟悉的 Android Vsync 信号。
当Vsync信号到来时,Flutter框架按照如图所示的顺序执行一系列动作:动画(Animate)、构建(Build)、布局(Layout)和绘制(Paint),最终生成场景( Scene)发送到下层并由GPU渲染到屏幕上。
动画阶段(Animation):因为动画会随着每个Vsync信号到来而改变状态,所以动画阶段是管线的第一阶段。
Build(构建)Flutter 就处于这个阶段,这个阶段需要重建的 Widget 都会在这个时候重建。然后调用熟悉的StatelessWidget.build()或State.build()。
布局阶段,此时各个显示元素的位置和大小将被确定。这是调用 RenderObject.performLayout() 的时候。
绘制阶段,这是调用 RenderObject.paint() 的时候。
以上是整个渲染管线的粗略工作流程。
Flutter 应用程序只需要在状态发生变化时启动渲染管道。当您的应用程序不执行任何操作时,无需重新渲染页面。因此,Vsync信号必须由Flutter发送。例如,我们都知道如果你的某个页面需要改变,你可以调用State.setState()。这次对Flutter框架的调用最终会发起一个请求,向下层发送Vsync信号。然后下层在Vsync信号到达时驱动渲染通道开始工作,最终在屏幕上显示新的页面。
图形管道
Flutter框架的渲染机制示意图。
整个渲染管线运行在UI线程中,由Vsync信号控制。当图像完成渲染后,将出现图层树。
图层树被发送到引擎。该模块将图层树调度到GPU线程,在GPU线程上合成图层树,然后使用Skia 2D渲染引擎进行渲染并发送到GPU进行显示。
这里提到图层树,是因为我们要分析的渲染管线的绘制阶段最终输出的就是这样的图层树。
所以绘制阶段并不是调用paint()函数那么简单,而是很多地方涉及到图层树的管理。
Flutter 只关心提供 GPU 显示数据。 GPU 的 VSync 信号与 UI 线程同步。 UI线程使用Dart创建抽象视图结构。该数据结构是在GPU线程中合成的一层,并将显示数据提供给Skia模块。渲染到GPU的数据通过OpenGL或Vulkan提供给GPU。
Widget
在Flutter中,大多数东西都是widget,而widget是不可变的,它们只支持一帧,不会在每一帧上直接更新。您必须使用小部件状态来更新。无状态和有状态小部件的基本功能是相同的。它们每帧都会重建,并有一个 State 对象,可以跨帧存储状态数据并刷新它。 Flutter 附带了适用于 Android 的 Skia。 Skia是一个跨平台的2D绘图工具库,因此可以内置到Flutter的iOS SDK中,使得Flutter Android SDK比iOS SDK小很多。
Widget 生命周期
StatelessWidget 无法更改,例如:Icon、Text 等。
如果显示后不需要更改控件,则应使用 StatelessWidget。
StatefulWidget 是有状态且可变的。
可能会根据用户操作或数据更改而改变其外观。 ? 版权归作者所有。商业转载请联系作者获得许可。非商业转载请注明来源。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。