Flutter:架构概览

概览

Flutter本质上是一个跨平台的UI工具集,允许在各自操作系统上复用同样的代码。
尽可能提供原生体验的高性能和复用代码。

开发中,Flutter应用在一个VM上运行,使得可在保留状态且无需重新编译情况下,进行热加载。
发行时,Flutter应用会直接通过AOT编译为机器码或者是JS。

分层模型

Flutter是一个可拓展的分层系统,可被视为各个独立组件的集合,上层组件依赖下层,上层无法越界访问更下层的组件,框架内各部分是可选可替代的。

分为框架、引擎、嵌入层
在这里插入图片描述

嵌入层

对于底层操作系统,Flutter应用程序的包装方式与其他原生应用相同,每个平台都会包含一个特定的嵌入层,提供一个程序入口,使得程序可以与底层操作系统进行协调、访问服务和管理事件循环队列。
对于不同平台,嵌入层使用的语言都不一样。Flutter代码可以作为模块集成到现有应用或作为应用主体。

引擎

主要使用C++编写,提供Flutter应用所需原语。
当需要绘制新一帧内容时,引擎将负责对需要合成的场景进行栅格化。
其提供Flutter核心API的底层实现:图形、文本布局等…

引擎将底层C++代码包装成Dart代码,通过dart:ui暴露给Flutter框架层。该库暴露了最底层的原语,包括用于驱动输入,图形等子系统的类

框架

开发者通过Flutter框架和Flutter交互,该框架提供了以Dart语言编写的现代响应式框架。
自下而上有:

Foundational and Annimation、Painting、Gestures

Foundational:基础类
Annimation:动画
Painting:绘画
Gestures:手势
向上层提供常用的抽象

渲染层

提供操作布局的抽象,操作层使得可以构建一颗可渲染对象的树,可动态更新。

Widget

组合的抽象,每个渲染层中的渲染对象在widget层中有一个对应的类。
widget层可让你自由组合需要复用的各种类,引入了响应式编程模型。

Material和Cupertino

提供了全面的widget层的原语组合,分别实现了Material和IOS设计规范。

其他更高层级的功能被拆分到不同的软件包中。

应用剖析在这里插入图片描述

  • Dart应用:将Widget合成预期的UI,实现业务。
  • 框架:提供API封装,将应用widget树构建在一个Scene中。
  • 引擎:将合成的Scene进行栅格化、封装Flutter进行封装,暴露功能给dart:ui API给框架、使用嵌入层API与平台进行整合。
  • 嵌入层:协调底层操作系统的服务、管理事件循环体系、暴露特定平台API给应用集成嵌入层。
  • 运行器:将嵌入层暴露的平台API合成为目标平台可运行的应用包。

响应式用户界面

Flutter是一个响应式的且伪声明式的UI框架,
随widget构造方法引入的新输入会随着其build方法传播给更低等级的widget;
而底层的widget中出现的修改也会沿着结构树通过event handler向上传播。
函数-响应式、指令-响应式都有出现,
前者是指widget的build方法中只包含其针对变化如何响应的表达式,
后者则包含一系列构造子元素的表达式,用于描述该widget如何响应变化。

Flutter,widget用来配置对象树的不可变类,这些widget管理单独的布局对象树,接着参与管理合成的布局对象树。

Flutter核心是一套高效的遍历树的变动的机制,将对象树转换为更底层的对象树,在树间传递更改。

build将状态转换为UI,在框架需要都可以被调用,可快速执行且没有额外影响,依赖DART的运行时特征:对象的快速实例化和清除。

Widgets

Flutter强调以widgets为组成单位。widgets是构建flutter应用界面的基础块,每个widget都是一部分不可变的UI声明。

widget通过布局组合形成一种层次结构关系,每个widget都嵌套在其父级的内部,可以通过父级接收上下文。从根布局(MaterialApp或CupertinoApp)开始,自上而下。

应用根据事件交互,通知框架替换层级中的旧widget为新的widget,比较新旧widget,高效更新。
Flutter拥有自己的UI控制实现,不使用系统自带。
这样提供了无限拓展性,不受系统提供的拓展限制。
Flutter可直接合成所有的场景,避免与原生平台来回切换,避免了性能瓶颈。
将应用的行为与操作系统的依赖解耦,实现不同平台,体验一致。

组成

widget通常由更小的且用途单一的widget组合而成,提供更强大的功能。
Flutter 在widget层中使用了widget来表示屏幕上的绘制、布局等
Flutter 在动画层,Animation和Tween涵盖了大部分的设计空间
Flutter 在渲染层,RenderObject用来描述布局、绘制、触摸判断等
Widget思想是 浅而广,最大限度地增加可能的组合数量,每个widget完成一件事,将核心功能抽象,如边距等基础功能,被实现为单独的组件

构建widget

build方法会返回一个新的元素树,这棵树更具体地表示了widget在ui中的部分。
框架会递归请求每个widget进行构建,直到整棵树都被具体的可渲染对象描述为止。
框架会将可渲染的对象缝合在一起,组合成可渲染对象树。

每个渲染帧,Flutter都可以根据变化的状态,调用build方法重建部分UI。
因此,build方法轻量且能快速返回widget,计算工作通过一些异步方法完成,并存储在状态中,由build使用。

widget状态

框架包含两种核心的widget:有无状态widget StatefulWidget / StatelessWidget
改变state时,调用setState来告知框架,调用State的构建方法来更新UI

Flutter将状态和widget对象分离,无需担心状态丢失,可随时创建新实例和复用已存在的状态对象

状态管理

通过context传递状态信息,子widget通过build(BuildContext context)方法接受父widget传入的信息,初始化所需数据。

随着widget树层级加深,依赖树形结构上下传递状态信息会变得十分困难。
InheritedWidget将一个共同的祖先结点包裹在widget树中
在这里插入图片描述

final studentState = StudentState.of(context);

通过of(context)会根据当前构建的上下文,返回类型为StudentState的在树中距离最近的祖先结点。
InheritedWidget包含updateShouldNotify()来判断widget是否需要重建。

provider用于状态管理,对InheritedWidget进行进一步报装,如flutter_hooks也可以用来替换状态至ui。

渲染过程

Flutter的渲染模型

Android系统提供了将自身绘制到Canvas对象的组件,接着使用C/C++编写的Skia图像引擎,调用CPU和GPU完成再设别上绘制。
一般的跨平台框架会在Android和IOS的UI底层库上创建一层抽象,程序代码通常使用JS进行编写,基于与系统进行交互来显示UI界面,当UI和应用逻辑有繁杂的交互时更会如此。

Flutter通过绕过系统UI组件库,使用自己的widget内容集,削减了抽象层的开销。
绘制Flutter图像内容的Dart代码被编译为机械码,使用平台提供的skia渲染,Flutter也嵌入自己的skia副本。

输入事件执行流程

  • User input 响应用户输入:对输入手势进行响应(点击效果等)
  • Animation 执行动画:由计时器触发界面更改
  • Build 构建组件:创建widget在屏幕上
  • Layout 组件布局:定位和测量屏幕上的元素 -----------------
  • Paint 绘画组件:将元素转换为虚拟表示 ----------------- Rendering渲染
  • Composition 整合组件:按绘画顺序覆盖组件 -----------------
  • Rasterize 光栅化:将输出翻译为GPU绘画指令

Widget到Element

build方法返回一棵基于当前应用状态来绘制UI的widget子树。
build方法会在必要时,根据状态引入新widget,如color为空时引入ColoredBox,image引入RawImage,Text引入RichText

构建时,Flutter会将widget转换为Element树,每个widget都有一个对应的Element
分为两种:
ComponentElement:其他Element的宿主
RenderObjectElement:参与布局或者绘制阶段的Element
在这里插入图片描述
RenderObjectElement 是底层 RenderObject 与对应的 widget 之间的桥梁。

对 widget 树做的任何操作(例如将 Text(‘A’) 替换成 Text(‘B’))都会返回一个新的 widget 对象集合。但这并不意味着底层呈现的内容必须要重新构建。 Element 树每一帧之间都是持久化的,因此起着至关重要的性能作用, Flutter 依靠该优势,实现了一种好似 widget 树被完全抛弃,而缓存了底层表示的机制。 Flutter 可以根据发生变化的 widget,来重建需要重新配置的 Element 树的部分。

布局和渲染

在渲染树中,每个节点的基类都是RenderObject,为布局和绘制定义了一个抽象模型。
每个RenderObject都了解其父节点的信息,但对于其子节点,除了访问和获得他们的布局约束,并没有更多的信息。

这样使得RenderObject拥有更高效的抽象能力。

构建时,Flutter会为Element树中的每个RenderObjectElement创建或更新其对应的一个从RenderObject对象。

在这里插入图片描述
大部分Flutter widget 由一个继承了RenderBox的子类的对象渲染的,其呈现出的RenderObject拥有固定的大小。提供了盒子限制模型,为每个widget关联了渲染的最小和最大的宽度和高度。

进行布局时,Flutter会以DFS遍历渲染树,将限制以自上而下的方式从父节点传递给子节点。
子节点若要确定自己的大小,必须循环父节点传递的限制。
子节点的响应方式是在父节点建立的约束内将大小以自下而上的方式传递给父节点。

遍历完一次树后,每个对象都通过父级约束而拥有了明确的大小,随时可以通过调用paint渲染。

盒子限制模型的对象布局的时间复杂度为O(n)
父节点可通过设定最大和最小的尺寸限制,决定其子节点对象的大小。
父节点可以决定子节点的宽度,然后自适应布局高度。

LayoutBuilder widget 的子节点可以得到从上层传递下来的约束,并合理利用该约束对象。

RenderObject根节点为RenderView,代表渲染树的总体输出。当平台需要渲染新一帧内容时,会调用一次compositeFrame方法,是RenderView的一部分。

compositeFrame创建一个SceneBuilder来触发当前画面的更新,更新完后,RenderView会将合成的画面传递给dart:ui中的Window.render方法来控制GPU进行渲染。

平台嵌入层

Flutter界面构建、布局、合成和绘制都由Flutter自己完成,获取纹理和联动应用底层的生命周期的方法,不可避免地根据平台特性而改变。Flutter引擎本身是平台无关,提供ABI接口设置并使用Flutter。

平台嵌入层提供一个入口,初始化Flutter引擎,获取UI和栅格化线程。嵌入层充当宿主操作系统和Flutter之间的粘合剂。还负责管理应用的声明周期。

Flutter集成其他代码

Flutter提供了多种代码交互机制,可以将原生代码嵌入Flutter,或者Flutter嵌入现有应用。

平台通道

Flutter通过 平台通道 调用自定义代码。通过创建一个常用的通道,开发者可以在Dart与使用Kotlin等语言编写的平台组件间发送和接收消息。

数据由Dart类型序列化为一种标准格式,再反序列化为kotlin等中的等效类型。
在这里插入图片描述

Web支持

。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/37878.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

chrome插件reading-time开发

本插件开发文档翻译于Google官方文档Chrome Extensions Tutorial: Reading time - Chrome Developers 一、reading-time reading-time项目的功能是 将预期的阅读时间添加到任何Chrome extension 和 Chrome Web Store documentation 页面里面 通过这个项目,我们可以…

网络套接字编程(三)(HTTP)

gitee仓库:https://gitee.com/WangZihao64/linux/tree/master/CalTcp 一、重谈协议 协议是一种“约定”,这种约定是双方都知道的。有了一致的约定,双方才能够正常地进行通信。协议在网络的第一篇博客中也提到过,协议是双方进行通…

图像增广:强化深度学习的视觉表现力

目录 摘要: 1. 图像增广简介 2. 图像增广的原理 3. 常见的图像增广技术 4. 如何在实际项目中应用图像增广 5.实际应用 摘要: 当今,深度学习已经在计算机视觉领域取得了令人瞩目的成就。图像增广作为一种数据处理技术,让我们…

一.CreateFileMapping实现的共享内存及用法

共享内存概念 1.在32位的Windows系统中,每一个进程都有权访问他自己的4GB(2324294967296)平面地址空间,没有段,没有选择符,没有near和far指针,没有near和far函数调用,也没有内存模式…

修改npm路径

npm config ls如果是第一次使用NPM安装包的话,在配置中只会看到prefix的选项,就是NPM默认的全局安装目录。但是如果有多次使用NPM安装包的话,就会看到cache和prefix两个路径。 新建两个文件夹node_global_modules和node_cache npm config s…

【CesiumJS入门】(7)绘制多段线(动态实时画线)

前言 鼠标左键添加点、右键完成绘制,单击右侧弹窗关闭按钮清空绘制。参考沙盒示例:Drawing on Terrain 直接上代码了 /** Date: 2023-07-12 18:47:18* LastEditors: ReBeX 420659880qq.com* LastEditTime: 2023-07-16 16:26:19* FilePath: \cesium-tyro-blog\s…

Verdi之波形展示nWave

6.nWave 6.1 添加波形文件 1.打开nWave界面,具体操作如下: 2.正式添加波形,使用快捷键G或者点击以下图标,选择需要的信号。 也可以在 n Trace中选中信号后,鼠标中键拖拽,或者ctrlw进行添加; 6…

R和python中dataframe读取方式总结

首先我有一个如图所示的文件 如果在python中读取 import pandas as pd df pd.read_csv("./6group_count.csv",index_col0) df而在R中读取的方式如下 df read.csv("./6group_count.csv",row.names 1)

MySQL---索引

目录 一、索引的分类 二、索引的底层原理是什么? 2.1、Innodb和MyIsAM两种引擎搜索数据时候的区别: 2.2、为什么MySQL(MyIsAM、Innodb)索引选择B树而不是B树呢? 2.3、Innodb的主键索引和二级索引(辅助…

【Ajax】笔记-Ajax案例准备与请求基本操作

案例准备HTML 按钮div <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>AJAX GET 请求</title&g…

2D、3D机器视觉各有优势与局限,融合应用将成工业领域生产新方式

在智能制造的浪潮中&#xff0c;制造行业生产线亟需转型升级&#xff0c;为国内机器视觉市场释放出了惊人的机器视觉技术及产品需求。在自动化工业质量控制和在线检测领域&#xff0c;2D机器视觉与3D机器视觉都具有重要的作用。那在机器视觉自动化场景中该如何选择合适的机器视…

python 乘法口诀

下面是一个用Python打印乘法口诀表的代码&#xff1a; print("乘法口诀表:")for i in range(1, 10):for j in range(1, i1):print(f"{j} {i} {i*j}", end"\t")print()

Blazor前后端框架Known-V1.2.4

V1.2.4 Known是基于C#和Blazor开发的前后端分离快速开发框架&#xff0c;开箱即用&#xff0c;跨平台&#xff0c;一处代码&#xff0c;多处运行。 Gitee&#xff1a; https://gitee.com/known/KnownGithub&#xff1a;https://github.com/known/Known 概述 基于C#和Blazor…

【图像处理】Python判断一张图像是否亮度过低,图片模糊判定

文章目录 亮度判断模糊判断 亮度判断 比如&#xff1a; 直方图&#xff1a; 代码&#xff1a; 这段代码是一个用于判断图像亮度是否过暗的函数is_dark&#xff0c;并对输入的图像进行可视化直方图展示。 首先&#xff0c;通过import语句导入了cv2和matplotlib.pyplot模块…

Element-Plus搭建CMS页面结构 引入第三方图标库iconfont(详细)

Element-Plus组件库使用 element plus组件库是由饿了么前端团队专门针对vue框架开发的组件库&#xff0c;专门用于电脑端网页的。因为里面集成了很多组件&#xff0c;所以使用他可以非常快速的帮我们实现网站的开发。 安装&#xff1a; npm install element-plus --save 引入…

jenkins 采用ssh方式连接gitlab连接不上

一、gitlab 添加jenkins服务器的公钥 jenkins 生成秘钥命令 ssh-keygen -t rsa2.jenkins 秘钥地址&#xff1a; cd /root/.ssh3.复制公钥 到gitlab 添加 cat id_rsa_pub4.添加私钥到jenkins cat id_rsa5.绑定&#xff08;顺利的话到这里就结束了&#xff09; &#xff0…

Linux下Lua和C++交互

前言 lua&#xff08;wiki 中文 官方社区&#xff1a;lua-users&#xff09;是一门开源、简明、可扩展且高效的弱类型解释型脚本语言。 由于其实现遵循C标准&#xff0c;它几乎能在所有的平台&#xff08;windows、linux、MacOS、Android、iOS、PlayStation、XBox、wii等&…

【条件与循环】——matlab入门

目录索引 if&#xff1a;else与elseif&#xff1a; for&#xff1a; if&#xff1a; if 条件语句块 endelse与elseif&#xff1a; if 条件代码块 elseif 条件代码块 else 代码块 endfor&#xff1a; for 条件循环体 end在matlab里面类似的引号操作都是包头又包尾的。上面的c…

postman测试接口出现404

postman测试接口出现404 1.用postman调试接口的过程中&#xff0c;出现404的情况&#xff0c;但是接口明明已调到了&#xff0c;而且数据也已经存入数据库了&#xff0c;这让我感到很疑惑。看网上的解决办法检查了我的路径&#xff0c;提交方式、参数类型等都是正确的&#xf…

安装adobe系列产品,提示错误代码81解决办法

安装adobe系列软件&#xff0c;如Photoshop、Premiere Pro、Illustrator等时&#xff0c;出现如下图提示错误代码81&#xff0c;如何解决呢&#xff1f;一起来看看。 解决方法一 (重启电脑等待5分钟再安装&#xff01;) 解决方法二 应用程序中打开Adobe Creative Cloud 点击…