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

article/2025/6/19 2:22:48

一、整体架构

官方文档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初始化、重组到最终绘制流程大致描述完毕


http://www.hkcw.cn/article/WMbXpCdwLw.shtml

相关文章

LeetCode 高频 SQL 50 题(基础版)之 【聚合函数】部分

题目:620. 有趣的电影 题解: select * from cinema where description !boring and id%21 order by rating desc题目:1251. 平均售价 题解: select p.product_id product_id,round(ifnull(sum(p.price*u.units)/sum(u.units),0)…

雪花算法的实际应用

什么场景下用雪花算法? 软件项目开发中,主键自动生成是基本需求。而各个数据库对于该需求也提供了相应的支持,比如:数据库自增(MySql,oracle)。但是在分布式环境中,分库分表之后,不同表生成全局唯一的ID是非…

Thinkphp6实现websocket

项目需要连接一台自动售货机&#xff0c;售货机要求两边用websocket连接,监听9997端口。本文实现了一个基于PHP的WebSocket服务器&#xff0c;用于连接自动售货机&#xff0c;支持start/stop/restart命令操作 1.新建文件 新建文件 /command/socket.php <?php namespace a…

痉挛性斜颈带来的困扰

当颈部不受控制地扭转歪斜&#xff0c;生活便被打乱了节奏。颈部肌肉异常收缩&#xff0c;导致头部不自觉偏向一侧或后仰&#xff0c;不仅让外观明显异于常人&#xff0c;还会引发持续的酸痛与僵硬感。长时间保持扭曲姿势&#xff0c;肩颈肌肉过度紧绷&#xff0c;甚至会牵连背…

【中国・珠海】2025 物联网与边缘计算国际研讨会(IoTEC2025)盛大来袭!

2025 物联网与边缘计算国际研讨会&#xff08;IoTEC2025&#xff09;盛大来袭&#xff01; 科技浪潮奔涌向前&#xff0c;物联网与边缘计算已成为驱动各行业变革的核心力量。在此背景下&#xff0c;2025 物联网与边缘计算国际研讨会&#xff08;IoTEC2025&#xff09;即将震撼…

一周学会Pandas2之Python数据处理与分析-数据重塑与透视-pivot() - 透视 (长 -> 宽,有限制)

锋哥原创的Pandas2 Python数据处理与分析 视频教程&#xff1a; 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili pivot() 是 pandas 中用于数据重塑的核心方法&#xff0c;它将长格式数据转换为宽格式数据&#xff0c;与 melt() 方…

WordPress通过简码插入bilibili视频

发布于&#xff1a;Eucalyptus-Blog 一、前言 B站是国内非常受欢迎的视频分享平台&#xff0c;上面不仅内容丰富&#xff0c;而且很多视频制作精良、趣味十足。很多人&#xff0c;比如我&#xff0c;就喜欢将B站的视频通过 iframe 嵌入到自己的网页中&#xff0c;但这段代码又…

【Unity博客节选】Timeline 的 Traversal mode参数

注&#xff1a;软件版本Unity 6.0 Timeline 1.8.7 作者&#xff1a;CSDN RingleaderWang 原文&#xff1a;《Unity第25期——Timeline结构及其源码浅析》 文章首发Github&#x1f44d;&#xff1a;《Timeline结构及其源码浅析》 Bilibili 视频版&#x1f44d;&#x1f44d;&a…

Constraints and Triggers

目录 Kinds of Constraints Single-Attribute Keys Multiattribute Key Foreign Keys Expressing Foreign Keys Enforcing Foreign-Key Constraints Actions Taken Attribute-Based Checks Timing of Checks Tuple-Based Checks Assertions Timing of Assertion Ch…

免费且好用的PDF水印添加工具

软件介绍 今天要给大家推荐一款超实用的PDF添加水印工具&#xff0c;它能够满足用户给PDF文件添加水印的需求&#xff0c;而且完全免费。 这款PDF添加水印的软件有着简洁的界面&#xff0c;操作简便&#xff0c;无需安装&#xff0c;解压后即可使用。 在使用前&#xff0c;先…

设计模式——面向对象设计六大原则

摘要 本文详细介绍了设计模式中的六大基本原则&#xff0c;包括单一职责原则、开放封闭原则、里氏替换原则、接口隔离原则、依赖倒置原则和合成复用原则。每个原则都通过定义、理解、示例三个部分进行阐述&#xff0c;旨在帮助开发者提高代码的可维护性和灵活性。通过具体代码…

DO指数GPU版本

大指数下DO指数模型计算优化 DO指数模型概述 DO指数&#xff08;Duranton-Overman Index&#xff09;是由Duranton和Overman于2005年提出的产业空间集聚测度方法&#xff0c;它通过分析企业间的精确地理距离分布来识别产业集聚模式。与传统集聚指标相比&#xff0c;DO指数具有…

工业物联网中的事件驱动采样架构及优化

论文标题 Event-Based Sampling Architecture and Optimization for Industrial Internet of Things 工业物联网中的事件驱动采样架构及优化 作者信息 Tejas Thosani Process Control Systems, Micron Technology Inc., Manassas, USA tthosanimicron.com Andres Prado Esp…

Windows | 总误按Num Lock?修改注册表永久禁用Numlk键使小键盘一直输入数字

先说需修改注册表的位置与键值 路径&#xff1a;HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout\ 二进制键&#xff1a;Scancode Map 键值&#xff1a; 00 00 00 00 00 00 00 00 01 00 00 00 00 00 45 00 00 00 00 00 00 00 00 00如下图&#xff1a; …

c#与halcon环境配置,导出算法库,使用halcon环境编程

目录 1. C#配置halcon运行环境 2.导出halcon算法库 3.使用方法 记录下C#配置halcon环境的方法&#xff0c;以及halcon导出库的使用方法。 1. C#配置halcon运行环境 VS版本&#xff1a; vs2019 halcon版本: 20.11 创建c#工程&#xff0c;点击“创建新项目”&#xff0c;…

tomcat yum安装

使用yum安装 yum install -y java-1.7.0-openjdk* tomcat* --disablerepoepel## java-1.7.0-openjdk* 注意&#xff1a;最终安装的是java-1.8.0版本## --disablerepoepel 禁用&#xff1a;EPEL源&#xff0c;防止版本冲突 java -version (2) 启停&#xff1a;Tomcat 7 s…

时间的基本概念与相关技术三

1.5 守时技术 所谓守时&#xff08;time keeping&#xff09;是指一个时频系统&#xff08;包括频标和分频钟&#xff09;对时间信号和时间信息的保持。频率标准&#xff08;简称频标&#xff09;的频率准确度、频率稳定度和守时系统的环境条件是决定守时能力的三个关键因素。…

云原生安全基石:Kubernetes 核心概念与安全实践指南

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. Kubernetes 架构全景 Kubernetes&#xff08;简称 K8s&#xff09;采用主从架构&#xff0c;由控制平面&#xff08;Control Plane&…

【python】uv管理器

uv是一个速度极快的 Python 包和项目管理器&#xff0c;用 Rust 编写。 安装 安装uv之前&#xff0c;确保你的电脑不需要安装了python 在Windows下&#xff0c;可以使用官方的脚本直接安装 powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.…

2021 年 12 月大学英语四级考试真题(第 1 2 3 套)——解析版——篇章题

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;目前中南大学MBA在读&#xff0c;也考取过HCIE Cloud Computing、CCIE Security、PMP、CISP、RHCE、CCNP RS、PEST 3等证书。&#x1f433; &…