一、概览
Flutter本质上是一个跨平台的UI工具集,允许在各自操作系统上复用同样的代码。
尽可能提供原生体验的高性能和复用代码。
开发中,Flutter应用在一个VM上运行,使得可在保留状态且无需重新编译情况下,进行热加载。
发行时,Flutter应用会直接通过AOT编译为机器码或者是JS。
参考链接:Flutter 架构概览 | Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
1.1 分层模型
Flutter是一个可拓展的分层系统,可被视为各个独立组件的集合,上层组件依赖下层,上层无法越界访问更下层的组件,框架内各部分是可选可替代的。
分为框架、引擎、嵌入层
嵌入层
对于底层操作系统,Flutter应用程序的包装方式与其他原生应用相同,每个平台都会包含一个特定的嵌入层,提供一个程序入口,使得程序可以与底层操作系统进行协调、访问服务和管理事件循环队列。
对于不同平台,嵌入层使用的语言都不一样。Flutter代码可以作为模块集成到现有应用或作为应用主体。
引擎
Flutter 引擎主要使用 C++ 编写,提供了应用程序所需的基本原语。当需要绘制新一帧内容时,引擎负责对需要合成的场景进行栅格化,并提供 Flutter 核心 API 的底层实现,包括图形和文本布局等功能。
引擎将底层的 C++ 代码包装成 Dart 代码,通过 dart:ui
库暴露给 Flutter 框架层。这个库提供了最底层的原语,包含了驱动输入、图形等子系统的类。
框架
开发者通过Flutter框架和Flutter交互,该框架提供了以Dart语言编写的现代响应式框架。
1.2 框架说明
名称 | 说明 |
---|---|
Foundational | 基础类 |
Annimation | 动画 |
Painting | 绘画 |
Gestures | 手势 |
Widget | 组合的抽象,每个渲染层中的渲染对象在widget层中有一个对应的类。 widget层可让你自由组合需要复用的各种类,引入了响应式编程模型。 |
Material和Cupertino | 提供了全面的widget层的原语组合,分别实现了Material和IOS设计规范。 |
1.3 应用剖析
-
Dart应用:将Widget合成预期的UI,实现业务。
-
框架:提供API封装,将应用widget树构建在一个Scene中。
-
引擎:将合成的Scene进行栅格化、封装Flutter进行封装,暴露功能给dart:ui API给框架、使用嵌入层API与平台进行整合。
-
嵌入层:协调底层操作系统的服务、管理事件循环体系、暴露特定平台API给应用集成嵌入层。
-
运行器:将嵌入层暴露的平台API合成为目标平台可运行的应用包。
1.4 响应式用户界面
Flutter是一个响应式的且伪声明式的UI框架,随widget构造方法引入的新输入会随着其build方法传播给更低等级的widget。
而底层的widget中出现的修改也会沿着结构树通过event handler向上传播。
函数-响应式、指令-响应式都有出现,
前者是指widget的build方法中只包含其针对变化如何响应的表达式,
后者则包含一系列构造子元素的表达式,用于描述该widget如何响应变化。
Flutter,widget用来配置对象树的不可变类,这些widget管理单独的布局对象树,接着参与管理合成的布局对象树。
Flutter核心是一套高效的遍历树的变动的机制,将对象树转换为更底层的对象树,在树间传递更改。
build将状态转换为UI,在框架需要都可以被调用,可快速执行且没有额外影响,依赖DART的运行时特征:对象的快速实例化和清除。
二、详细说明
2.1 Widgets
Flutter强调以widgets为组成单位。widgets是构建flutter应用界面的基础块,每个widget都是一部分不可变的UI声明。
widget通过布局组合形成一种层次结构关系,每个widget都嵌套在其父级的内部,可以通过父级接收上下文。从根布局(MaterialApp或CupertinoApp)开始,自上而下。
应用根据事件交互,通知框架替换层级中的旧widget为新的widget,比较新旧widget,高效更新。
Flutter拥有自己的UI控制实现,不使用系统自带。
这样提供了无限拓展性,不受系统提供的拓展限制。
Flutter可直接合成所有的场景,避免与原生平台来回切换,避免了性能瓶颈。
将应用的行为与操作系统的依赖解耦,实现不同平台,体验一致。
2.1.1 组成
widget通常由更小的且用途单一的widget组合而成,提供更强大的功能。
Flutter 在widget层中使用了widget来表示屏幕上的绘制、布局等
Flutter 在动画层,Animation和Tween涵盖了大部分的设计空间
Flutter 在渲染层,RenderObject用来描述布局、绘制、触摸判断等
Widget思想是 浅而广,最大限度地增加可能的组合数量,每个widget完成一件事,将核心功能抽象,如边距等基础功能,被实现为单独的组件
2.1.2 构建
build方法会返回一个新的元素树,这棵树更具体地表示了widget在ui中的部分。
框架会递归请求每个widget进行构建,直到整棵树都被具体的可渲染对象描述为止。
框架会将可渲染的对象缝合在一起,组合成可渲染对象树。
每个渲染帧,Flutter都可以根据变化的状态,调用build方法重建部分UI。
因此,build方法轻量且能快速返回widget,计算工作通过一些异步方法完成,并存储在状态中,由build使用。
2.1.3 状态管理
框架包含两种核心的widget:有无状态widget StatefulWidget / StatelessWidget
改变state时,调用setState来告知框架,调用State的构建方法来更新UI
Flutter将状态和widget对象分离,无需担心状态丢失,可随时创建新实例和复用已存在的状态对象
通过context传递状态信息,子widget通过build(BuildContext context)方法接受父widget传入的信息,初始化所需数据。
随着widget树层级加深,依赖树形结构上下传递状态信息会变得十分困难。
InheritedWidget将一个共同的祖先结点包裹在widget树中
通过of(context)会根据当前构建的上下文,返回类型为StudentState的在树中距离最近的祖先结点。
InheritedWidget包含updateShouldNotify()来判断widget是否需要重建。
provider用于状态管理,对InheritedWidget进行进一步报装,如flutter_hooks也可以用来替换状态至ui。
2.1.4 Widget到Element
build方法返回一棵基于当前应用状态来绘制UI的widget子树。
build方法会在必要时,根据状态引入新widget,如color为空时引入ColoredBox,image引入RawImage,Text引入RichText
构建时,Flutter会将widget转换为Element树,每个widget都有一个对应的Element
分为两种:
ComponentElement:其他Element的宿主
RenderObjectElement:参与布局或者绘制阶段的Element
2.2 渲染过程
2.2.1 Flutter的渲染模型
Android系统提供了将自身绘制到Canvas对象的组件,接着使用C/C++编写的Skia图像引擎,调用CPU和GPU完成再设别上绘制。
一般的跨平台框架会在Android和IOS的UI底层库上创建一层抽象,程序代码通常使用JS进行编写,基于与系统进行交互来显示UI界面,当UI和应用逻辑有繁杂的交互时更会如此。
Flutter通过绕过系统UI组件库,使用自己的widget内容集,削减了抽象层的开销。
绘制Flutter图像内容的Dart代码被编译为机械码,使用平台提供的skia渲染,Flutter也嵌入自己的skia副本。
2.2.2 输入事件执行流程
User input 响应用户输入:对输入手势进行响应(点击效果等)
Animation 执行动画:由计时器触发界面更改
Build 构建组件:创建widget在屏幕上
Layout 组件布局:定位和测量屏幕上的元素
Paint 绘画组件:将元素转换为虚拟表示
Composition 整合组件:按绘画顺序覆盖组件
Rasterize 光栅化:将输出翻译为GPU绘画指令
2.3 Flutter集成原生代码
Flutter提供了多种代码交互机制,可以将原生代码嵌入Flutter,或者Flutter嵌入现有应用。
平台通道
Flutter通过 平台通道 调用自定义代码。通过创建一个常用的通道,开发者可以在Dart与使用Kotlin等语言编写的平台组件间发送和接收消息。
数据由Dart类型序列化为一种标准格式,再反序列化为kotlin等中的等效类型。