这是我第三篇Flutter相关博客 欢迎 查看个人前两篇 Flutter实现篇html
Flutter是Google用以帮助开发者在Ios和Android两个平台开发高质量原生应用的全新移动UI框架.我开始认识Flutter时,经历了三个Flutter重要历史版本.前端
此后愈来愈多的人开始关注到Flutter。web
在 Flutter 诞生以前,已经有许多跨平台 UI 框架的方案,好比基于 WebView 的 Cordova、AppCan 等,还有使用 HTML+JavaScript 渲染成原生控件的 React Native、Weex 等。Flutter 则开辟了一种全新的思路,从头到 尾重写一套跨平台的 UI 框架,包括 UI 控件、渲染逻辑甚至开发语言。算法
从图中能够看出 Flutter主要被分为两层 Framework层和Flutter Engine.网络
Framework层所有使用Dart编写,有完整UI框架的API,并预写了Android(MaterialDesign)和IOS的(Cupertino)风格的UI,极大方便了开发移动端.数据结构
Framework 底层是 Flutter 引擎, 引擎主要负责图形绘制 (Skia)、 文字排版 (libtxt) 和提供 Dart 运行时, 引擎所有使用 C++实现.多线程
在看Flutter框架前,咱们先看一下其余跨平台框架的设计架构
咱们知道Flutter的Framework层是使用了Dart语言编写,那Dart语言有哪些优点呢?下面分为几个点来阐述框架
DartVM的内存分配策略很是简单,建立对象时只须要在现有堆上移动指针,内存增加始终是线形的,省去了查找可用内存段的过程异步
Dart中相似线程的概念叫作Isolate,每一个Isolate之间是没法共享内存的,因此这种分配策略可让Dart实现无锁的快速分配。
Dart的垃圾回收也采用了多生代算法,新生代在回收内存时采用了“半空间”算法,触发垃圾回收时Dart会将当前半空间中的“活跃”对象拷贝到备用空间,而后总体释放当前空间的全部内存如图.
整个过程当中Dart只须要操做少许的“活跃”对象,大量的没有引用的“死亡”对象则被忽略,这种 多生代无锁垃圾回收器,专门为UI框架中常见的大量Widgets对象建立和销毁优化,很是适合Flutter框架中大量Widget重建的场景.
代码体积优化(Tree Shaking),编译时只保留运行时须要调用的代码(不容许反射这样的隐式引用),因此庞大的Widgets库不会形成发布体积过大。
Dart支持两种编译模式:
在debug模式下使用JIT编译,生成srcipt/bytecode进行解释执行,能够支持HotReload(热重载),修改代码,保持便可在设备上看到效果. 而在Release下 AOT编译生成Machine Code,高效的运行.
对于移动端的交互来讲,大多数状况下都是在等待状态,等待网络请求,等待用户输入等.那么设想一下,发起一个网络请求只在一个线程中能够进行吗?固然网络请求确定是异步的(注意这里说的异步而多线程并不是一个概念.),事实验证是能够的,Flutter就采用了Dart这种单线程机制,省去了多线程上下文切换带来的性能损耗.(对于高耗时操做,也一样支持多线程操做,经过Isolate开启,不过注意这里的多线程,内存是没法共享的.)
当一个Dart的方法开始执行时,他会一直执行直至达到这个方法的退出点。换句话说Dart的方法是不会被其余Dart代码打断的。 当一个Dart应用开始的标志是它的main isolate执行了main方法。当main方法退出后,main isolate的线程就会去逐一处理消息队列中的消息。
有了消息队列,而后有了循环去读取消息队列中的消息,就能够有单线程去执行异步消息的能力. 通常的消息使用dart:async中使用Future来支持异步消息.
在讲Flutter Engin层时,咱们先讲一下屏幕绘制的原理.
咱们都知道显示器以固定的频率刷新,好比 iPhone的 60Hz、iPad Pro的 120Hz。当一帧图像绘制完毕后准备绘制下一帧时,显示器会发出一个垂直同步信号(VSync),因此 60Hz的屏幕就会一秒内发出 60次这样的信号。
而且通常地来讲,计算机系统中,CPU、GPU和显示器以一种特定的方式协做:CPU将计算好的显示内容提交给 GPU,GPU渲染后放入帧缓冲区,而后视频控制器按照 VSync信号从帧缓冲区取帧数据传递给显示器显示。
做为一个专职Android开发,看过Android的绘图机制,经过SurfaceFlinger 和HAL层之间的工做机制发现和Flutter的很像,那么IOS的如何呢?我的推测屏幕的绘图机制是同样的,只是不一样平台有不一样实现.
Flutter只关心向 GPU提供视图数据,GPU的 VSync信号同步到 UI线程,UI线程使用 Dart来构建抽象的视图结构,这份数据结构在 GPU线程进行图层合成,视图数据提供给 Skia引擎渲染为 GPU数据,这些数据经过 OpenGL或者 Vulkan提供给 GPU.
因此 Flutter并不关心显示器、视频控制器以及 GPU具体工做,它只关心 GPU发出的 VSync信号,尽量快地在两个 VSync信号之间计算并合成视图数据,而且把数据提供给 GPU.
在 Flutter 界面渲染过程分为 3 个阶段: 布局、绘制、合成.
而布局阶段,有三个重要的对象.RenderObject、Element、Widget.
Widget是开发常常接触的控件,默认是只读的.
Element 是 Flutter 用来分离控件树和真正的渲染 对象的中间层, 控件用来描述对应的 element 属性,控件重建后可能会复用同一个 element.
RenderObject 负责提供配置信息并建立具体的 Element。
Element 持有真正负责布局、 绘制和碰撞测试 (hit test) 的 RenderObject 对象.
那么这样,若是控件的属性发生了变化 (由于控件的属性是只 读的, 因此变化也就意味着从新建立了新的控件树), 可是其树上每一个节点的类型没有变化时, element 树和 render 树能够彻底重用原来的对象 (由于 element 和 render object 的属性都是可变的)
传统布局,如Android可能须要屡次Measure,计算宽高。Flutter 采用约束进行单次测量布局. 整个布局过程当中只须要深度遍历一次,极大的提高效能。
渲染对象树中的每一个对象都会在布局过程当中接受父 对象的 Constraints 参数,决定本身的大小, 而后父对象 就能够按照本身的逻辑决定各个子对象的位置,完成布局过程.
子对象不存储本身在容器中的位置, 因此在它的位置发生改变时并不须要从新布局或者绘制. 子对象的位 置信息存储在它本身的 parentData 字段中,可是该字段由它的父对象负责维护,自身并不关心该字段的内容。
同时也由于这种简单的布局逻辑, Flutter 能够在某些节 点设置布局边界 (Relayout boundary), 即当边界内的任 何对象发生从新布局时, 不会影响边界外的对象, 反之亦然.
文中参考的资料以下