Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

2019年9月8日12:52:08 发表评论 67 views

Flutter 是谷歌2018年发布的跨平台移动UI框架。与 react native 通过 Javascript 开发不同,Flutter 的编程语言是Dart,所以执行时并不需要 Javascript 引擎,但实际效果最终也通过原生渲染。

Google 出品,Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染。

图形性能媲美原生应用

其他框架只是做了OEM封装,Flutter可以直接操作Skia进行绘制。

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

跨平台: 移动、Web、桌面、嵌入

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

框架结构

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

从该架构图可知,Flutter框架可分为Framework层和Engine层;

框架(Framework)部分是用Dart语言写的,也是本系列文章主要涉及的部分。

引擎(Engine)部分是用C++实现的。引擎为框架提供支撑,也是连接框架和系统(Android/iOS)的桥梁。

Flutter Framework: 整个框架层都是用Dart语言实现,该层提供一套基础库, 用于处理动画、绘图和手势等。并且基于绘图封装了一套 UI组件库,并且细分为两种风格的组件 。

Foundation、Animation、Painting、Gestures 为 Dart 实现的 UI 层,提供动画、手势及绘制。

Rendering 渲染层,依赖 UI 层,在运行时 Rendering 层会构建一个 Widget 树,当有变化时,会根据一定的算法计算出有变化的部分,然后更新 Widget 树。

Widgets 层是 Flutter 提供的的一套基础组件库,在基础组件库之上,Flutter 还提供了 Material 和 Cupertino 两种视觉风格的组件库。

Materail : Android风格的Widget

Cupertino: IOS风格的Widget

Flutter Engine

Skia 是一个开源的二维图形库,提供各种常用的 API,并可在多种软硬件平台上运行。谷歌 Chrome 浏览器、Chrome OS、安卓、火狐浏览器、火狐操作系统以及其它许多产品都使用它作为图形引擎。

Skia 由谷歌出资管理,任何人都可基于 BSD 免费软件许可证使用 Skia。Skia 开发团队致力于开发其核心部分, 并广泛采纳各方对于 Skia 的开源贡献。

因为没有使用原生的 UI 和绘制框架,所以才保证了 Flutter 的高性能体验。

Flutter Engine: 这是一个纯 C++实现的 SDK,其中囊括了 Skia引擎、Dart运行时、文字排版引擎等。不过说白了,它就是 Dart的一个运行时,它可以以 JIT、JIT Snapshot 或者 AOT的模式运行 Dart代码。在代码调用 dart:ui库时,提供 dart:ui库中 Native Binding 实现。 不过别忘了,这个运行时还控制着 VSync信号的传递、GPU数据的填充等,并且还负责把客户端的事件传递到运行时中的代码。

sdk源码

…/sdk/flutter/packages/flutter/lib

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

Flutter for Web

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

通过对比,可以发现,web框架层和mobile的几乎一模一样。因此只需要重新实现一下引擎和嵌入层,不用变动Flutter API就可以完全可以将UI代码从Android / IOS Flutter App移植到Web。Dart能够使用Dart2Js编译器把Dart代码编译成Js代码。大多数原生App元素能够通过DOM实现,DOM实现不了的元素可以通过Canvas来实现。

通信

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

得益于 Engine 层,Flutter 甚至不使用移动平台的原生控件, 而是使用自己 Engine 来绘制 Widget (Flutter的显示单元),而 Dart 代码都是通过 AOT 编译为平台的原生代码,所以 Flutter 可以 直接与平台通信,不需要JS引擎的桥接。同时 Flutter 唯一要求系统提供的是 canvas,以实现UI的绘制。

对于Android平台,Flutter引擎的C/C++代码是由NDK编译,在iOS平台,则是由LLVM编译,两个平台的Dart代码都是AOT编译为本地代码,Flutter应用程序使用本机指令集运行。Flutter正是是通过使用相同的渲染器、框架和一组widget,来同时构建iOS和Android应用,而无需维护两套独立的代码库。

通过platform channels 和本地进行通信。

通过MethodChannel,Native也能调用Flutter的方法,这是一个双向的通道。

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

关于VSync

Android显示器运行在60帧/秒左右,一帧大概16.6ms。

绘制间隔时间大于16ms会出现卡顿现象。

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染
Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

图形渲染

Rendering Pipeline

在Flutter框架中存在着一个渲染流水线(Rendering pipline)。这个渲染流水线是由垂直同步信号(Vsync)驱动的,而Vsync信号是由系统提供的,如果你的Flutter app是运行在Android上的话,那Vsync信号就是我们熟悉的Android的那个Vsync信号。

当Vsync信号到来以后,Flutter 框架会按照图里的顺序执行一系列动作: 动画(Animate)、构建(Build)、布局(Layout)和绘制(Paint),最终生成一个场景(Scene)之后送往底层,由GPU绘制到屏幕上。

动画(Animate)阶段:因为动画会随每个Vsync信号的到来而改变状态(State),所以动画阶段是流水线的第一个阶段。

构建(Build)在这个阶段Flutter,在这个阶段那些需要被重新构建的Widget会在此时被重新构建。也就是我们熟悉的StatelessWidget.build()或者State.build()被调用的时候。

布局(Layout)阶段,这时会确定各个显示元素的位置,尺寸。此时是RenderObject.performLayout()被调用的时候。

绘制(Paint)阶段,此时是RenderObject.paint()被调用的时候。

以上是整个渲染流水线的一个大致的工作过程。

Flutter app只有在状态发生变化的时候需要触发渲染流水线。当你的app什么都不做的时候是不需要重新渲染页面的。所以,Vsync信号需要Flutter app去调度。比如我们都知道如果你的某个页面需要发生变化的时候有可能会调用State.setState(),这个调用Flutter框架最终会发起一个调度Vsync信号的请求给底层。然后底层会在Vsync信号到来的时候驱动渲染流水线开始运作,最后把新的页面显示到屏幕上。

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

Graphics Pipeline

Flutter框架渲染机制的一个示意图。

整个渲染流水线是运行在UI线程里的,以Vsync信号为驱动,在框架渲染完成之后会输出layer tree。

layer tree被送入engine,engine会把layer tree调度到GPU线程,在GPU线程内合成(compsite)layer tree,然后由Skia 2D渲染引擎渲染后送入GPU显示。

这里提到layer tree是因为我们即将要分析的渲染流水线绘制阶段最终输出就是这样的layer tree。

所以绘制阶段并不是简单的调用paint()函数这么简单了,而是很多地方都涉及到layer tree的管理。

Flutter只关心向 GPU提供视图数据,GPU的 VSync信号同步到 UI线程,UI线程使用 Dart来构建抽象的视图结构,这份数据结构在 GPU线程进行图层合成,视图数据提供给 Skia引擎渲染为 GPU数据,这些数据通过 OpenGL或者 Vulkan提供给 GPU。

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

Widget

在Flutter中,大多数东西都是widget,而Widget是不可变的,仅支持一帧,并且在每一帧上不会直接更新,要更新而必须使用Widget的状态。无状态和有状态 widget 的核心特性是相同的,每一帧它们都会重新构建,有一个State对象,它可以跨帧存储状态数据并恢复它。 Flutter 上 Android 自带了 Skia,Skia是一个 2D的绘图引擎库,跨平台,所以可以被嵌入到 Flutter的 iOS SDK中,也使得 Flutter Android SDK要比 iOS SDK小很多。

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

Widget lifecycle

一个 StatelessWidget 是不能被改变的,比如:Icon、Text等。

如果你的控件一旦显示,就不需要再做任何的变更,那么你应该使用 StatelessWidget。

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

一个 StatefulWidget 是有状态的,可变的。

它可以改变自己的外观,以响应用户的操作或者数据的变化。

比如:CheckBox、Switch..

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

State lifecycle

Flutter原理深度解析:Dart语言,Flutter Engine引擎,响应式设计模式,原生渲染

作者:九天星辰
链接:https://juejin.im/post/5d71d2f2518825103e545bdc
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: