Jetpack Compose 可组合项的生命周期

点击查看:可组合项的生命周期 官网

在本页中,您将了解可组合项的生命周期以及 Compose 如何确定可组合项是否需要重组。

生命周期概览

正如管理状态文档中所述,一个组合将描述应用的界面,并通过运行可组合项来生成。组合是描述界面的可组合项的树结构。

当 Jetpack Compose 首次运行可组合项时,在初始组合期间,它将跟踪您为了描述组合中的界面而调用的可组合项。然后,当应用的状态发生变化时,Jetpack Compose 会安排重组。重组是指 Jetpack Compose 重新执行可能因状态更改而更改的可组合项,然后更新组合以反映所有更改。

组合只能通过初始组合生成且只能通过重组进行更新。重组是修改组合的唯一方式。

要点:可组合项的生命周期通过以下事件定义:进入组合,执行 0 次或多次重组,然后退出组合。

在这里插入图片描述
图 1. 组合中可组合项的生命周期。进入组合,执行 0 次或多次重组,然后退出组合。

重组通常由对 State 对象的更改触发。Compose 会跟踪这些操作,并运行组合中读取该特定 State 的所有可组合项以及这些操作调用的无法跳过的所有可组合项。

注意:可组合项的生命周期比视图、activity 和 fragment 的生命周期更简单。当可组合项需要管理生命周期确实更复杂的外部资源或与之互动时,您应使用效应。

如果某一可组合项多次被调用,在组合中将放置多个实例。每次调用在组合中都有自己的生命周期。

@Composable
fun MyComposable() {Column {Text("Hello")Text("World")}
}

在这里插入图片描述
图 2. 组合中 MyComposable 的表示。如果某一可组合项多次被调用,在组合中将放置多个实例。如果某一元素具有不同颜色,则表明它是一个独立实例。

组合中可组合项的剖析

组合中可组合项的实例由其调用点进行标识。Compose 编译器将每个调用点都视为不同的调用点。从多个调用站点调用可组合项会在组合中创建多个可组合项实例。

关键术语:调用点是调用可组合项的源代码位置。这会影响其在组合中的位置,因此会影响界面树。

在重组期间,可组合项调用的可组合项与上个组合期间调用的可组合项不同,Compose 将确定调用或未调用的可组合项,对于在两次组合中均调用的可组合项,如果其输入未更改,Compose 将避免重组这些可组合项。

保留身份对于将附带效应与可组合项相关联十分重要,这样它们才能成功完成,而不是每次重组时都重新启动。

请参考以下示例:

@Composable
fun LoginScreen(showError: Boolean) {if (showError) {LoginError()}LoginInput() // This call site affects where LoginInput is placed in Composition
}@Composable
fun LoginInput() { /* ... */ }@Composable
fun LoginError() { /* ... */ }

在上面的代码段中,LoginScreen 将有条件地调用 LoginError 可组合项,并始终调用 LoginInput 可组合项。每个调用都有唯一的调用点和源位置,编译器将使用它们对调用进行唯一识别。

在这里插入图片描述
图 3. 出现状态更改和重组时,组合中 LoginScreen 的表示。颜色相同,表示尚未重组。

即使 LoginInput 从第一次被调用变为第二次被调用,LoginInput 实例仍将在不同重组中保留下来。此外,由于 LoginInput 不包含任何在重组过程中更改过的参数,因此 Compose 将跳过对 LoginInput 的调用。

添加额外信息以促进智能重组

多次调用同一可组合项也会多次将其添加到组合中。如果从同一个调用点多次调用某个可组合项,Compose 就无法唯一标识对该可组合项的每次调用,因此除了调用点之外,还会使用执行顺序来区分实例。这种行为有时是必需的,但在某些情况下会导致发生意外行为。

@Composable
fun MoviesScreen(movies: List<Movie>) {Column {for (movie in movies) {// MovieOverview composables are placed in Composition given its// index position in the for loopMovieOverview(movie)}}
}

在上面的示例中,Compose 除了使用调用点之外,还使用执行顺序来区分组合中的实例。如果列表底部新增了一个 movie,Compose 可以重复使用组合中既有的实例,因为这些实例在列表中的位置没有发生变化,因此这些实例的 movie 输入是相同的。

在这里插入图片描述
图 4. 列表底部新增元素时,组合中 MoviesScreen 的表示。可以重复使用组合中的 MovieOverview 可组合项。MovieOverview 中的相同颜色表示该可组合项尚未重组。

但是,如果因在列表顶部或中间新增内容,移除项目或对项目进行重新排序而导致 movies 列表发生改变,将导致输入参数在列表中的位置已更改的所有 MovieOverview 调用发生重组。例如,如果 MovieOverview 使用附带效应提取影片图像,这一点将非常重要。如果在使用附带效应的过程中发生重组,系统就会取消重组并重新开始。

@Composable
fun MovieOverview(movie: Movie) {Column {// Side effect explained later in the docs. If MovieOverview// recomposes, while fetching the image is in progress,// it is cancelled and restarted.val image = loadNetworkImage(movie.url)MovieHeader(image)/* ... */}
}

在这里插入图片描述
图 5. 向列表中添加新元素后,组合中 MoviesScreen 的表示。MovieOverview 可组合项不能重复使用,并且所有附带效应都将重启。MovieOverview 中不同的颜色表示该可组合项已重组。

理想情况下,我们认为 MovieOverview 实例的身份与传递到该实例的 movie 的身份相关联。如果我们对影片列表进行重新排序,理想情况下,我们会以类似方式在组合树中对实例进行重新排序,而不是将每个 MovieOverview 可组合项与不同影片实例进行重组。您可以使用 Compose 来告诉运行时,您要使用哪些值来标识树的给定部分:key 可组合项。

通过调用带有一个或多个传入值的键可组合项来封装代码块,这些值将被组合以用于在组合中标识该实例。key 的值不必是全局唯一的,只需要在调用点处调用可组合项的作用域内确保其唯一性即可。在此示例中,每个 movie 都需要一个在 movies 的作用域内具有唯一性的 key;movie 也可以与应用中其他位置的其他可组合项共享该 key。

@Composable
fun MoviesScreenWithKey(movies: List<Movie>) {Column {for (movie in movies) {key(movie.id) { // Unique ID for this movieMovieOverview(movie)}}}
}

使用上述代码后,即使列表中的元素发生变化,Compose 也能识别 MovieOverview 的各个调用,还可以重复使用这些调用。

在这里插入图片描述
图 6. 向列表中添加新元素后,组合中 MoviesScreen 的表示。由于 MovieOverview 可组合项具有唯一键,因此 Compose 会识别未更改的 MovieOverview 实例,并且可重复使用它们;它们的附带效应将继续执行。

要点:使用 key 可组合项帮助 Compose 识别组合中的可组合项实例。当从同一个调用点调用多个可组合项,且这些可组合项包含附带效应或内部状态时,这一点非常重要。

一些可组合项提供对 key 可组合项的内置支持。例如,LazyColumn 接受在 items DSL 中指定自定义 key。

@Composable
fun MoviesScreenLazy(movies: List<Movie>) {LazyColumn {items(movies, key = { movie -> movie.id }) { movie ->MovieOverview(movie)}}
}

如果输入未更改,则跳过

如果组合中已有可组合项,当所有输入都处于稳定状态且没有变化时,可以跳过重组。

稳定类型必须符合以下协定:

  • 对于相同的两个实例,其 equals 的结果将始终相同。
  • 如果类型的某个公共属性发生变化,组合将收到通知。
  • 所有公共属性类型也都是稳定。

有些归入此协定的重要常见类型会被 Compose 编译器视为稳定版,即使没有使用 @Stable 注解将其明确标记为稳定版,也是如此:

  • 所有基元值类型:Boolean、Int、Long、Float、Char 等。
  • 字符串
  • 所有函数类型 (lambda)
    所有这些类型都可以遵循稳定协定,因为它们是不可变的。由于不可变类型绝不会发生变化,它们就永远不必通知组合更改方面的信息,因此遵循该协定就容易得多。

注意:所有深层不可变的类型都可以被安全地视为稳定类型。

Compose 的 MutableState 类型是一种众所周知稳定但可变的类型。如果 MutableState 中存储了值,状态对象整体会被视为稳定对象,因为 State 的 .value 属性如有任何更改,Compose 就会收到通知。

当作为参数传递到可组合项的所有类型都很稳定时,系统会根据可组合项在界面树中的位置来比较参数值,以确保相等性。如果所有值自上次调用后未发生变化,则会跳过重组。

要点:如果所有输入都稳定并且没有更改,Compose 将跳过重组可组合项。比较使用了 equals 方法。

Compose 仅在可以证明稳定的情况下才会认为类型是稳定的。例如,接口通常被视为不稳定类型,并且具有可变公共属性的类型(实现可能不可变)的类型也被视为不稳定类型。

如果 Compose 无法推断类型是否稳定,但您想强制 Compose 将其视为稳定类型,请使用 @Stable 注解对其进行标记。

// Marking the type as stable to favor skipping and smart recompositions.
@Stable
interface UiState<T : Result<T>> {val value: T?val exception: Throwable?val hasError: Booleanget() = exception != null
}

在上面的代码段中,由于 UiState 是接口,因此 Compose 通常认为此类型不稳定。通过添加 @Stable 注解,您可以告知 Compose 此类型稳定,让 Compose 优先选择智能重组。这也意味着,如果将该接口用作参数类型,Compose 会将其所有实现视为稳定。

要点:如果 Compose 无法推断某个类型的稳定性,请为该类型添加 @Stable 注解,让 Compose 优先选择智能重组。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算能RISC-V通用云开发空间编译pytorch @openKylin留档

终于可以体验下risc-v了&#xff01; 操作系统是openKylin&#xff0c;算能的云空间 尝试编译安装pytorch 首先安装git apt install git 然后下载pytorch和算能cpu的库&#xff1a; git clone https://github.com/sophgo/cpuinfo.git git clone https://github.com/pytorc…

2.5网安学习第二阶段第五周回顾(个人学习记录使用)

本周重点 ①多进程和多线程 1、进程和线程 2、多线程爆破 ②Redis数据库 1、Redis的使用 2、Redis持久化 3、Redis未授权免密登录 ③嗅探和Python攻击脚本 1、嗅探&#xff08;端口扫描和IP扫描&#xff09; 2、SCAPY的应用 3、Python攻击脚本&#xff08;SYN半连接…

CI/CD 之 gitlab-runner 部署与踩坑

前言 去年花时间研究了一下 CI/CD , 自己部署了一套 gitlab-runner 玩了一下&#xff0c;部署过程之后遇到了不少问题&#xff0c;把之前的踩坑与部署记录分享一下。 简介 gitlab-runner是一个开源项目&#xff0c;用于运行 Pipeline 作业并将结果发送回 GitLab。 它与 Git…

NLP_构建GPT模型并完成文本生成任务

文章目录 搭建GPT模型&#xff08;解码器&#xff09;构建文本生成任务的数据集训练过程中的自回归文本生成中的自回归&#xff08;贪婪搜索&#xff09;完整代码小结 搭建GPT模型&#xff08;解码器&#xff09; GPT 只使用了 Transformer的解码器部分&#xff0c;其关键组件…

【探讨】光场显示技术的研究现状与发展趋势

摘要&#xff1a;目前常用的三维显示技术&#xff0c;一般是通过人眼的双目视差和视觉暂留效应实现的三维效果。由于丢失了深度信息&#xff0c;会引起辐辏调节冲突&#xff0c;使观看者产生不适感。光场显示是通过复现物体表面光线的真三维显示技术&#xff0c;其拥有良好的用…

Zabbix 远程监控主机

目录 1、安装 Zabbix 安装客户端 服务端测试通讯 Web页面添加主机 2、监控 Nginx 自定义脚本监控 Nginx web配置台 3、监控 MySQL 配置模版文件 配置Web界面 1、安装 Zabbix node-12 作为zabbix的被监控端&#xff0c;提供mysql服务器&#xff0c;配置zabbix监控node…

(HAL)STM32F103C6T8——软件模拟I2C驱动0.96寸OLED屏幕

一、电路接法 电路接法参照江科大视频。 二、相关代码及文件 说明&#xff1a;代码采用hal库&#xff0c;通过修改江科大代码实现。仅OLED.c文件关于引脚定义作了hal库修改&#xff0c;并将宏定义OLED_W_SCL(x)、OLED_W_SDA(x)作了相关修改。 1、OLED.c void OLED_I2C_Init(voi…

Encoder-decoder 与Decoder-only 模型之间的使用区别

承接上文&#xff1a;Transformer Encoder-Decoer 结构回顾 笔者以huggingface T5 transformer 对encoder-decoder 模型进行了简单的回顾。 由于笔者最近使用decoder-only模型时发现&#xff0c;其使用细节和encoder-decoder有着非常大的区别&#xff1b;而huggingface的接口为…

golang 项目中配置gin的web框架

1.go 初始化 mod文件 go mod init gin-ranking 2.gin的crm框架 go get -u github.com/gin-gonic/gin 3.go.mod爆红解决

【汽车电子】万字详解汽车标定与XCP协议

XCP协议基础 文章目录 XCP协议基础一、引言1.1 什么是标定1.2 什么时候进行标定1.3 标定的意义 二、XCP协议简介2.1 xcp简介2.2 XCP如何加快开发过程&#xff1f;2.3 XCP的主要作用 三、XCP工作过程3.1 工作过程3.2 通讯模型3.3 测量与标定 四、XCP报文解析4.1 数据包报文格式4…

利用Ubuntu22.04启动U盘对电脑磁盘进行格式化

概要&#xff1a; 本篇演示利用Ubuntu22.04启动U盘的Try Ubuntu模式对电脑磁盘进行格式化 一、说明 1、电脑 笔者的电脑品牌是acer(宏碁/宏基) 开机按F2进入BIOS 开机按F12进入Boot Manager 2、Ubuntu22.04启动U盘 制作方法参考笔者的文章&#xff1a; Ubuntu制作Ubun…

力扣日记2.22-【回溯算法篇】47. 全排列 II

力扣日记&#xff1a;【回溯算法篇】47. 全排列 II 日期&#xff1a;2023.2.22 参考&#xff1a;代码随想录、力扣 47. 全排列 II 题目描述 难度&#xff1a;中等 给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 示例 1&#xff1a; 输…