Flutter基础专题

Flutter专题

对比:
WebView:   优点:丰富的控件库、动态化、良好的技术社区、测试自动化等等    
           缺点:渲染效率和java的执行能力比较差,页面的加载速度和用户体验都不尽如人意

RN: 使用类HTML+JS的UI创建逻辑,生成对应的原生页面,讲页面的渲染工作交给了系统,以渲染效率有很大优势。但由于RN代码通过JS桥接的方式转换为原生控件,所以安卓/iOS系统间的差异影响非常大,对应各个平台的适配很麻烦。

为啥flutter
Flutter: 开源跨平台 UI 框架 Flutter。
        重写了一套跨平台的UI框架,渲染引擎是依靠Skia*图形库实现。  Flutter中的控件树直接由渲染引擎和高性能本地ARM*代码直接绘制,不需要通过中间对象(Web应用中的虚拟DOM和真实DOM,原生App中的虚拟控件和平台控件)来绘制,是它有接近原生页面的性能,帮助我们提供更好的用户体验。
        同时支持JIT和AOT*编译。JIT编译方式使其在开发阶段可以--热重载,在开发时省去的构建过程,提高开发效率。而在Release运行时采用AOT的编译方式,使执行效率非常高,让Release版本发挥更好的性能。

        //Skia 是一个 Google 开源的 C++ 二维图形库,提供各种常用的API,并可在多种软硬件平台上运行。Skia是一个完整的2D图像库,包括图像、动画、文本绘制功能
// Skia是跨平台的,所以可以被嵌入到 Flutter的 iOS SDK中,而不用去研究 iOS闭源的 Core Graphics / Core Animation。
        //ARM 成熟的 架构 是处理器
        //AOT ((Ahead-Of-Time - 预先编译)它们必须在执行前编译成机器码,  在android里面,jit会把程序实时编译为机器字节码,然后虚拟机读取,打开程序

flutter架构和实现原理
1、Flutter 使用Dart语言。
    1)Dart一般情况下是运行在DartVM上,但是也可以编译为ARM代码直接运行在硬件上,考虑一下与其它硬件的结合。
    2)Dart支持AOT和JIT两种编译方式。
    3)Dart可以利用独特的隔离区(Isolate)实现多线程。而且不共享内存,可实现无锁快速分配。
    4)分代垃圾回收,非常适合 UI 框架中常见的大量 Widgets 对象创建和销毁的优化。
    5)在为创建的对象分配内存时,Dart是在现有的堆上移动指针,保证内存的增长是线性的,省了查找可用内存的过程

Flutter架构也是采用的分层设计,从上到下一次为: Embedder(嵌入器)、Engine、Framework

Embedder是嵌入层,做好这一层的适配 Flutter 基本可以嵌入到任何平台上去;
Engine层主要包含 Skia、Dart 和 Text。Skia 是开源的二位图形库;Dart 部分主要包括 runtime、Garbage Collection、编译模式支持等;Text 是文本渲染。
Framework在最上层。我们的应用围绕 Framework 层来构建,因此也是本文要介绍的重点。

Flutter基础专题

5.【Rendering】是框架中的渲染库。控件的渲染主要包括三个阶段:布局(Layout)、绘制(Paint)、合成(Composite)。

Flutter基础专题
图2: Flutter 流水线
首先是获取到用户的操作,然后你的应用会因此显示一些动画,接着 Flutter 开始构建 Widget 对象。
Widget 对象构建完成后进入渲染阶段,这个阶段主要包括三步:
* 布局元素:决定页面元素在屏幕上的位置和大小;
* 绘制阶段:将页面元素绘制成它们应有的样式;
* 合成阶段:按照绘制规则将之前两个步骤的产物组合在一起。
最后的光栅化由 Engine 层来完成。


在渲染阶段,控件树(widget)会转换成对应的渲染对象(RenderObject)树,在 Rendering 层进行布局和绘制。

在布局时 Flutter 深度优先遍历渲染对象树。数据流的传递方式是从上到下传递约束,从下到上传递大小。也就是说,父节点会将自己的约束传递给子节点,子节点根据接收到的约束来计算自己的大小,然后将自己的尺寸返回给父节点。整个过程中,位置信息由父节点来控制,子节点并不关心自己所在的位置,而父节点也不关心子节点具体长什么样子。

Flutter基础专题


【Widget】控件层。所有控件的基类都是 Widget,Widget 的数据都是只读的, 不能改变。所以每次需要更新页面时都需要重新创建一个新的控件树。每一个 Widget 会通过一个 RenderObjectElement 对应到一个渲染节点(RenderObject),可以简单理解为 Widget 中只存储了页面元素的信息,而真正负责布局、渲染的是 RenderObject。
Widget -> RenderObjectElement 对应到一个渲染节点-> RenderObject
RenderObjectElement 树会尽量保持重用。由于 RenderObjectElement 持有对应的 RenderObject,所有 RenderObject 树也会尽可能的被重用。
Flutter基础专题

如果想把方形的颜色换成黄色,将圆形的颜色变成红色,由于控件是不能被修改的,需要重新生成两个新的控件 Rectangle yellow 和 Circle red。由于只是修改了颜色属性,所以 Element 和 RenderObject 都被重用,而之前的控件树会被释放回收。
Flutter基础专题

widget 是view吗
widget是对页面UI的一种描述。widget在渲染的时候会转化成element,Element相比widget相比于widget增加了上下文的信息。。element是对应widget,在渲染树的实例化节点。由于widget是immutable的,所以同一个widget可以同时描述多个渲染树中的节点。
所以同一个widget可以同时描述多个渲染树中的节点。但是Element是描述固定在渲染书中的某一个特定位置的点。

简单点说widget作为一种描述是可以复用的,但是element却跟需要绘制的节点一一对应。element绘制时会转化成rendObject。RendObject才是真正经过layout的paint并绘制在屏幕上的对象,在flutter中有三套渲染相关的tree,分别是widget tree & relement tree &rendObject tree。

Flutter基础专题

flutter是响应式的框架。在某一时刻页面的布局,可能受不同的输入源的影响。
Element这层实际上做了对某一时刻事件的汇总,在将真正需要修改的部分同步到真实的
rendObject tree上。

7. 最后是【Material】 & 【Cupertino】,这是在 Widget 层之上框架为开发者提供的基于两套设计语言实现的 UI 控件,可以帮助我们的 App 在不同平台上提供接近原生的用户体验。

///// 为什么widget都是immutable
flutter界面开发是一种响应式编程,主张sImple is fast, flutter设计的初衷希望数据变更时发送通知到对应的可变更节点。由上到下重新create widget树进行刷新。

如何触发树更新
1. 全局更新:调用runApp(rootWidget),一般flutter启动时调用后不再会调用
2. 局部子树更新, 将该子树做StatefullWidget的一个子widget,并创建对应的State类实例,通过调用state.setState() 触发该子树的刷新

 

StatefullWidget vs StatelessWidget
1. StatelessWidget:无中间状态变化的widget,需要更新展示内容就得通过重新new,flutter推荐尽量使用StatelessWidget
2. StatefullWidget:存在中间状态变化,那么问题来了,widget不是都immutable的,状态变化存储在哪里?flutter 引入state的类用于存放中间态,通过调用state.setState()进行此节点及以下的整个子树更新。单纯改变数据是不会引发UI改变的

Flutter基础专题

 

Flutter基础专题