Jetpack Compose 如何布局解析

news2024/11/25 0:45:48

文章目录

  • 前言
  • 1、@Composable 函数的编译器处理
  • 2、UI 树的构建与状态管理
  • 3、测量与布局
  • 4、重组机制(Recomposition)
  • 5、性能优化机制
  • 总结


前言

Jetpack Compose 的布局解析包含以下核心环节:编译器处理UI 树的构建与状态管理测量与布局、以及重组机制。以下是结合源码的深入解析。

1、@Composable 函数的编译器处理

@Composable 是 Compose 中的核心注解,用于标记 Composable 函数,表示该函数会参与 Compose 的重组机制。

编译器的作用
Compose 编译器会将标注为 @Composable 的函数转换为支持 Composer 和 Recomposition 的代码。以下是编译前后的对比:

原始代码:

@Composable
fun Greeting(name: String) {
    Text("Hello, $name!")
}

编译后的伪代码:

fun Greeting(name: String, composer: Composer?, key: Int) {
    composer.startRestartGroup(key) // 开始重组
    if (composer.shouldSkip()) {    // 判断是否跳过重组
        composer.skipCurrentGroup()
    } else {
        Text("Hello, $name!")       // 渲染 Text 组件
    }
    composer.endRestartGroup()      // 结束重组
}

关键源码位置
Composer 类:

  • 位于 androidx.compose.runtime 包中,是 Compose Runtime 的核心组件。
  • 负责管理重组范围(startRestartGroup/endRestartGroup)和跳过未改变的 UI 代码。

2、UI 树的构建与状态管理

Compose 使用 SlotTable 和 Composer 构建 UI 树并管理其状态。

SlotTable 的作用
SlotTable 是一个内部的数据结构,用于记录 UI 树的状态和结构。它包含了以下内容:

  • Key:用于标识每个 Composable 函数。
  • Value:存储与节点相关的数据,例如子节点的引用、布局信息等。

工作流程:

1、Composer 将 Composable 函数解析为节点。
2、解析结果存储在 SlotTable 中。

val slotTable = SlotTable()
val composer = Composer(slotTable)
composer.startRestartGroup(1234) // 开始解析 Key 为 1234 的组
Text("Hello, Compose!")
composer.endRestartGroup()       // 结束解析

相关源码位置

  • SlotTable 类:
    位于 androidx.compose.runtime 包中,核心方法包括 ensureCapacity 和 recordGroup。
  • Composer 类:
    管理 SlotTable 的增删改操作。

3、测量与布局

Compose 使用 LayoutNode 和 MeasurePolicy 实现测量与布局。
测量流程
Compose 布局解析的核心在于 测量约束传递子节点布局

  • Constraints:描述宽度、高度的限制条件。
  • MeasurePolicy:定义节点的测量逻辑,包括如何计算子节点的位置。

源码示例:
以下是 Compose 内部如何实现 Column 布局的一个简化示例:

val measurePolicy = MeasurePolicy { measurables, constraints ->
    var totalHeight = 0
    val placeables = measurables.map { measurable ->
        val placeable = measurable.measure(constraints)
        totalHeight += placeable.height
        placeable
    }
    layout(constraints.maxWidth, totalHeight) {
        var yPosition = 0
        placeables.forEach { placeable ->
            placeable.place(0, yPosition)
            yPosition += placeable.height
        }
    }
}
  • measurables.measure(constraints):对子节点进行测量。
  • layout:定义自身大小并放置子节点。
    关键源码位置
    MeasurePolicy 类:
    位于 androidx.compose.ui.layout.MeasurePolicy。
    LayoutNode 类:
    位于 androidx.compose.ui.node.LayoutNode。

4、重组机制(Recomposition)

重组是 Compose 的核心优化机制。它通过比较 SlotTable 的状态,仅更新发生变化的部分 UI。

状态与重组
Compose 使用 MutableState 和 remember 来追踪状态。当状态变化时,Composer 会标记对应的 UI 节点需要重新执行。

示例:

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }
    Button(onClick = { count++ }) {
        Text("Count: $count")
    }
}

当 count 发生变化时,Composer 仅重组 Text 节点,而不会更新其他部分。

伪代码:

fun Counter(composer: Composer?) {
    composer.startRestartGroup(key = 123)
    val count = composer.remember { mutableStateOf(0) }
    Button(onClick = { count.value++ }) {
        Text("Count: ${count.value}")
    }
    composer.endRestartGroup()
}

composer.shouldSkip():检查节点是否需要跳过。
remember:记录状态,用于触发重组。

5、性能优化机制

为了减少不必要的重组,Compose 提供了以下优化工具:
1、derivedStateOf:派生状态,用于合并多个状态变化,避免频繁重组。
2、remember:缓存计算结果,避免重复执行。

示例:

val derivedState = derivedStateOf { count * 2 }
Text("Derived Count: ${derivedState.value}")

总结

1、编译器阶段:
转换 @Composable 函数,生成支持 Composer 和重组的代码。
2、构建 UI 树:
使用 Composer 构建 SlotTable,记录 UI 组件信息。
3、测量布局:
通过 Constraints 和 MeasurePolicy 确定组件大小与位置。
4、状态更新:
管理组件状态,触发高效重组,更新变化的 UI 节点。

Compose 的解析流程从代码到最终渲染,严格遵循上述四步,使其能够在保持声明式编程风格的同时,达到高性能的动态更新能力。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【StarRocks】starrocks 3.2.12 【share-nothing】 多Be集群容器化部署

文章目录 一. 集群规划二.docker compose以及启动脚本卷映射对于网络环境变量 三. 集群测试用户新建、赋权、库表初始化断电重启扩容 BE 集群 一. 集群规划 部署文档 https://docs.starrocks.io/zh/docs/2.5/deployment/plan_cluster/ 分类描述FE节点1. 主要负责元数据管理、…

LLaMA-Factory 上手即用教程

LLaMA-Factory 是一个高效的大型语言模型微调工具,支持多种模型和训练方法,包括预训练、监督微调、强化学习等,同时提供量化技术和实验监控,旨在提高训练速度和模型性能。 官方开源地址:https://github.com/hiyouga/L…

Java基础面试题01-请描述Java中JDK和JRE的区别?

什么是 JDK? JDK 全称 Java Development Kit,中文叫“Java 开发工具包”。 它是给 Java 开发者用的工具箱,里面有一切写代码、编译代码、调试代码所需要的工具。 JDK 包括什么? Java 编译器(javac)&…

Ubuntu20.04下安装向日葵

向日葵远程控制app官方下载 - 贝锐向日葵官网 下载Ununtu版的图形版本的安装deb包SunloginClient_15.2.0.63064_amd64.deb 直接执行 sudo dpkg -i SunloginClient_15.2.0.63064_amd64.deb 的话会报错: 如果在Ubuntu20.04里直接执行sudo apt install libgconf-2-4安装libgco…

Typora+PicGo+云服务器搭建博客图床

文章目录 前言一. 为什么要搭建博客图床?1.1 什么是图床?1.2 为什么要搭建博客图床? 二. 安装软件三. 配置阿里云OSS3.1 注册,开通对象储存3.2 创建bucket3.3 找到你的地域节点3.4 accessKeyId和accessKeySecret3.5 给你的阿里云账户充值 四. 配置4.1 配…

Python的3D可视化库 - vedo (2)visual子模块 基本可视化行为

文章目录 1. visual模块的继承关系2. 基类CommonVisual的方法2.1 获取对象信息2.1.1 对象本身信息2.1.2 对象的查找表2.1.3 对象标量范围2.1.4 对象缩略图 2.2 呈现对象2.2.1 在窗口显示1.2.2 对象可见性 2.2.3 对象颜色2.2.4 对象透明度 2.3 添加标度条2.3.1 2D标度条2.3.2 3D…

常用Rust日志处理工具教程

在本文中,我想讨论Rust中的日志。通过一些背景信息,我将带您了解两个日志库:env_logger和log4rs。最后,我将分享我的建议和github的片段。 Rust log介绍 log包是Rust中日志API的事实标准,共有五个日志级别&#xff1…

废品买卖回收管理系统|Java|SSM|Vue| 前后端分离

【重要①】前后端源码万字文档部署文档 【重要②】正版源码有问题包售后 【包含内容】 【一】项目提供非常完整的源码注释 【二】相关技术栈文档 【三】源码讲解视频 【其它服务】 【一】可以提供远程部署安装,包扩环境 【…

案例研究|阿特斯的JumpServer分布式部署和多组织管理实践

苏州阿特斯阳光电力科技有限公司(以下简称为阿特斯)是一家集太阳能光伏组件制造和为全球客户提供太阳能应用产品研发、设计、制造、销售的专业公司。 阿特斯集团总部位于加拿大,中国区总部位于江苏省苏州市。通过全球战略和多元化的市场布局…

tongweb安全整改

一 禁止以root账号运行tongweb服务 1 如果是首次安装须创建普通用户安装tongweb 2 如果已经使用root账号安装了tongweb 2.1 创建普通用户 2.2 使用root账号授予tongweb安装目录宿主权限为普通用户 2.3赋权成功后,后续启动tongweb服务必须为普通用户 二 tongRDS隐…

快速识别模型:simple_ocr,部署教程

快速识别图片中的英文、标点符号、数学符号、Emoji, 模型会输出图片中文字行的坐标位置、最低得分、识别结果。当前服务用到的模型:检测模型、数字识别、英文符号识别。 一、部署流程 1.更新基础环境 apt update2.安装miniconda wget https://repo.anaconda.com/…

tcpdump抓包 wireShark

TCPdump抓包工具介绍 TCPdump,全称dump the traffic on anetwork,是一个运行在linux平台可以根据使用者需求对网络上传输的数据包进行捕获的抓包工具。 tcpdump可以支持的功能: 1、在Linux平台将网络中传输的数据包全部捕获过来进行分析 2、支持网络层…

HarmonyOS4+NEXT星河版入门与项目实战(11)------Button组件

文章目录 1、控件图解2、案例实现1、代码实现2、代码解释3、运行效果4、总结1、控件图解 这里我们用一张完整的图来汇整 Button 的用法格式、属性和事件,如下所示: 按钮默认类型就是胶囊类型。 2、案例实现 这里我们实现一个根据放大和缩小按钮来改变图片大小的功能。 功…

YOLOV5 /onnx模型转换成rknn

上两篇文章讲述了pytorch模型下best.pt转换成onnx模型,以及将onnx进行简化成为best-sim.onnx, 接下来这篇文章讲述如何将onnx模型转换成rknn模型,转换成该模型是为了在rk3568上运行 1.创建share文件夹 文件夹包含以下文件best-sim.onnx,rknn-tookit2-…

【51单片机】LCD1602液晶显示屏

学习使用的开发板:STC89C52RC/LE52RC 编程软件:Keil5 烧录软件:stc-isp 开发板实图: 文章目录 LCD1602存储结构时序结构 编码 —— 显示字符、数字 LCD1602 LCD1602(Liquid Crystal Display)液晶显示屏是…

如何使用AWS Lambda构建一个云端工具(超详细)

首发地址(欢迎大家访问):如何使用AWS Lambda构建一个云端工具(超详细) 1 前言 1.1 无服务器架构 无服务器架构(Serverless Computing)是一种云计算服务模型,它允许开发者构建和运行…

【Isaac Sim】相关问题汇总

目录 一、安装点击Install时报错二、启动时报 Failed to create any GPU devices三、加载Isaac Sim自带模型或示例时报 Isaac Sim is not responding 一、安装点击Install时报错 报错: request to https://asset.launcher.omniverse.nvidia.com/… failed, reason:…

Spring-02-springmvc

2. 什么是SpringMVC 2.1. 概述 Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。 为什么要学习SpringMVC呢? Spring MVC的特点: 轻量级,简单易学高效 , 基于请求响应的MVC框架与Spring兼容性好,无缝…

深度学习之目标检测的技巧汇总

1 Data Augmentation 介绍一篇发表在Big Data上的数据增强相关的文献综述。 Introduction 数据增强与过拟合 验证是否过拟合的方法:画出loss曲线,如果训练集loss持续减小但是验证集loss增大,就说明是过拟合了。 数据增强目的 通过数据增强…

qt添加模块

以QtNetwork模块为例 方式一 扩展-qt vs tools-qt project settings 方式二 右键选中项目-属性-qt project settings 方法三 在此界面选择select modules,即可进行相应模块添加