当前位置: 首页 > news >正文

Compose原理 - 整体架构与主流程

一、整体架构

官方文档Jetpack Compose 架构层  |  Android DevelopersCompose分层有所阐述:

其中

Runtime提供Compose基础运行能力包括StateSide-effectsCompositionLocal、Composition等等相关API

UI涉及到绘制部分,主要是LayoutNode,Modifiler相关

Foundation提供ColumnRow“设计系统无关”组件

Matieria提供Material Design相关能力比如主题ColorStyle

其中Runtime主要包含CompositionComposition, Recomposer, ComposeNode, RecomposeScope主要组件。除此之外,还有State相关的Snapshot的部分。这些是Compose得以实现核心主要阐述也就这部分架构

Compose源码架构

Jatpack Compose工具包形式集成Android绘制体系所以本质嵌入DecorViewContent换言之Compose组织内容最终绘制ComposeView再将ComposeView添加DecorView如此Compose便集成到AndroidView体系

上图几个重要

Composition可视为Composer容器主要负责与外部其他角色进行对接内部包含了一个Composer。如上图,一般情况下,一个DecorView包含一个Composition,即一个Activity对应一个Composition。如果使用TabRowBoxWithConstraints组件内部调用SubcomposeLayout从而创建多个Composition实例

Composer代表一个Compose内部构建重组等一个整体调度管理

SlotTable可以理解为实现Compose具体数据结构其内部主要两个数组成员IntArray类型的groupsArray类型slots其中groups用来记录一个group基本信息和其parent group从而可以构建一个groupslots用来存储每个group具体数据对于这两个数组成员具体操作通过Gap Buffer方式进行处理这是一种数据插入过程中移动Gap区域而不是数组元素方式达到数据更新目的Gap区域移动情况,仅仅通过几个指针操作快速访问数据由于Compose整体结构相对稳定Gap移动频率相对因此大部分数组访问达到O(1)时间复杂度架构图看到实际上每个Composition包含两个SlotTable一个用于写入一个用于读取写入后通过同步机制数据同步用于写入的SlotTable读写隔离有助于频繁操作过程中提高性能

GroupSlotTable数据结构,通过内部的parent属性记录其父Group,从而整体上可以构建为一个树形结构。可以简单理解一个Composable(一个自定义或内置Composable函数)对应一个Group不同类型的Composable对应不同Group类型因此一个Compose,实际上就是Group

Recomposer用于触发管理Compose树的组建和重组Recomposer内部有一个while循环当前DecorViewviewTreeLifecycle的ON_CREATE启动随后如果compositon被标记需要重组,则进行重组流程否则挂起等待

Snapshot快照系统用于State版本进行管理Snapshot的思想类似Git版本管理系统即,父分支快照基于自身拉出一个子分支快照,子快照只可以看到到自身快照内的State值的变更,其他分支相同State变更不可见。子快照可以通过apply接口将自身变更合入到父分支快照。换言之,父快照的值对子快照是可见的,子快照对父快照是不可见的,一直到子快照apply()。每次重组都会创建一个快照重组结束后apply快照快照,同时,快照也是ThreadLocal的,即是线程隔离的。这样每次重组访问State值的版本都是相互隔离影响重组完成后merge

RecomposeScopeComposeSlotTable通过group表达,但并非所有的group都是重组group很多类型为了重组group范围进行标记圈定创建重组group创建对应RecomposeScope保存起来state变更导致重组通过当前state对应scope找到重组范围进行重组

ApplierSlotTable存储只是存储了Compose结构信息以及组合过程中涉及rememberstate数据信息而具体绘制LayoutNode负责Applier就是作为ComposeLayoutNode之间桥梁初次组件或者后续重组完成之后通过Applier通知LayoutNode随后LayoutNode根据提供信息发生了变化Composable(保存在changes中)进行绘制

ChangeList:Composition中changes变量对应具体类型ChangeList存储Composable具体变化这些变化会通过Applier最终体现为LayoutNode变更

LayoutNode:Composable在绘制层面结构体Compose最终转化为LayoutNodemeasuredraw都是LayoutNode进行

二、Compose运行流程

Compose运行流程概述初始化、Composition(组合/重组并收集变更信息)、Applier(应用变更信息)、LayoutNode测量绘制

1. 初始化

Compose Runtime中的ComponentActivity提供setContent扩展方法用来ComposeView嵌入Android固有View体系中。ComposeView首先创建AndroidComposeViewAndroidComposeView通过addView加入到Android View树。Compose设计跨平台AndroidComposeView是针对Android平台的一些具体实现Compose绘制结果最终体现在AndroidComposeView上,AndroidComposeViewonMeasureonLayoutdispatchDraw最终传递Compose体系LayoutNode如此构成ComposeAndroid固有View体系结合

ComposeView中,同时也会RecomposerComposition进行初始化Recomposer用来重组管理,Composition代表Compose组合树的容器。

2. Composition(“组合/重组“变更信息)

2.1 首次组合

一步setConent过程调用RecomposercomposeInitial开始Compose树初始组合也就是构建Compose过程

composingRecomposer重要方法每次组合/重组都会调用可视为真正组合/重组起点为了叙述方便“组合”“重组”统一表述重组composing开始重组首先通过Snapshot创建一个快照副本,后续本次重组读写State这个快照范围进行不会影响其他快照。当然,其他快照也不会影响本次重组快照这样每次重组使用数据都是相互隔离

创建快照开始调用Composition进行重组流程每个Composition有一个Composer执行具体重组动作我们所有@Composable修饰的自定义函数称作ComposablesetContentcontent lambda也是一个ComposableComposer通过invokeComposable开始执行content lambda由此开始一系列Composable递归调用构建Compose我们其中一个Composable为例,每个Composable执行过程通过startXXXGroupSlotTable构建一个Group这个Group将被保存SlotTablegroups数组中。Group在不断创建过程中与Composable函数一样保持的对应的嵌入关系,也就是父子关系。后续会将Composable内相应数据(Group本身数据,函数参数、remember、state值等)保存这个Group对应Slots数组

创建Group通过addRecomposeScope创建一个RecomposeScope这个RecomposeScope代表Groupstate变更对应变化范围随后这个scope本身也会作为对应Group的数据通过updateValue存SlotTableslots数据里

以上完成scope通过insertSlots将其保存changeListWriter通过scope可以找到对应Group及其数据所以过程可以理解新建/变更group暂存changeListWriter

通过Composable不断递归调用整个Compose构建完毕实际上就是StlotTableGroup构建完毕并且构建过程group信息(全量)本暂存changeListWriter待进行具体测量、布局和绘制

2.2 重组

Compose特点之一就是响应式编程,数据变化驱动页面变化这个过程称为重组最长重组便是Composable读取state变更导致重组过程如下

Recomposer每次重组时创建Snapshot时,会注册该Snapshot的read/wri

te监听。在重组过程中,如果遇到某个Composable读取了某个State,就会把该State存储到Composable对应的RecomposerScope内,并将该scope与state的对应关系存储在observations中。当对State进行write写入时, Recomposer会通过Snapshot的writeObserver监听到写入动作,并且通知CompositionComposition通过遍历observations取出state对应scope然后加入invalidations缓存,随后也会将本composition作为invalid加入到Recomposer的compositionInvalidations缓存。

另一方面,Recomposer本身通过WindowRecomposer将自身onCreate声明周期绑定onCreate运行runRecomposeAndApplyChanges函数内部有一个while循环,运行频率会和vsync对齐。平时挂起只要compositionInvalidations有了变更就会开始运行其运行过程compositionInvalidations的compostion取出, 调用其recompose函数recompose之前invalidationsscope取出找到对应Group调用Composer的doCompose进行变更

state变更可能导致Composable位置移动删除插入这些转化SlotTable对为Group操作更新SlotTableGroup变更信息保存changeListWriter

上面过程可以看出state变化并不同步导致compose立即更新而是存在

invalidations等待下一vsync信号处理

3. Applier(应用变更信息)

现在无论初始组合还是重组最终变更信息保存changeListWriter我们来看changeListWriter如何最终转变具体页面变更

重组过程每一个Group操作最后转变一条指令通知给changeListWriter比如新建一个Group会调用changeListWriterinsertSlots函数insertSlotsChangeListpush一条指令这条指令保存在ChangeListoptions。RecomposerrunRecomposeAndApplyChanges在后续会调用composition.applyChanges随后取出options指令进行执行

具体执行每种指令具体转化Options一个具体子类例如创建一个Node GroupinsertSlotsInsertNodeFixup执行随后通知作为root的LayoutNode,进行创建group对应的LayoutNode并加入其LayoutNode树的对应位置。

每种Group新建移动删除操作最后变成响应layoutNode新建移动删除操作

4. LayoutNode测量、布局和绘制

LayoutNode结构变更完了随后需要将其绘制出来整个过程主要分为MeasureLayoutDrawMeasureAndLayoutDelegateLayoutNode测量代理执行测量具体方法每次LayoutNode变更会将变更layoutNode存储MeasureAndLayoutDelegaterelayoutNodes然后会通过传统的方式通知AndroidComposeView invalid此时onMeasure会被回调随后onMeasure调用measureAndLayout取出MeasureAndLayoutDelegaterelayoutNodes缓存然后进行下到上重新测量工作。Layout过程类似

测量布局完毕AndroidComposeViewdispatchDraw系统调用此时通过构建更新LayoutNode对应layer将其绘制封装CanvasAndroidCanvas从而完成绘制工作

此处可见绘制过程只对变更LayoutNode进行绘制由此之前重组的差量变更过程有意义

至此Compose初始化、重组到最终绘制流程大致描述完毕

相关文章:

  • 基于Python学习《Head First设计模式》 第一章 策略模式
  • 2025年全国青少年信息素养大赛复赛C++算法创意实践挑战赛真题模拟强化训练(试卷3:共计6题带解析)
  • stm32——SPI协议
  • JDK21深度解密 Day 8:Spring Boot 3与虚拟线程整合
  • JVM 核心组件深度解析:堆、方法区、执行引擎与本地方法接口
  • 【课堂笔记】标签传播算法Label Propagation Algorithm(LPA)
  • VMware-workstation安装教程--超详细(附带安装包)附带安装CentOS系统教程
  • 在QT中,利用charts库绘制FFT图形
  • 安装win11之后,电脑经常会跳出“无法在此设备上加载驱动程序”的提示。无法加载的驱动程序分别为“pcdsrvc_x64.pkms”“iqvw64e.sys”
  • 学习海康VisionMaster之表面缺陷滤波
  • 在 RK3588 上通过 VSCode 远程开发配置指南
  • MySQL访问控制与账号管理:原理、技术与最佳实践
  • 软件工程方法论:在确定性与不确定性的永恒之舞中寻找平衡
  • Redis 常用数据类型和命令使用
  • Linux环境搭建MCU开发环境
  • MCP架构全解析:从核心原理到企业级实践
  • Kubernetes架构与核心概念深度解析:Pod、Service与RBAC的奥秘
  • Protos-SIP:经典 SIP 协议模糊测试工具!全参数详细教程!Kali Linux教程!
  • C#WinForm程序时方法很多时Form.cs文件会很长,如何分别写入多个文件,partial class的作用体现出来了。
  • MyBatis01
  • 专门做酒店设计的网站/百度搜索关键词优化
  • 网站运营与管理的一个目的/网络软文是什么
  • javaweb可以做网站吗/seo编辑培训
  • 小视频网站建设/百度搜索竞价推广
  • 网站页面制作公司/怎样制作网站
  • 深圳网站设计九曲/qq推广引流网站