https://developer.android.google.cn/develop/ui/compose/lifecycle?hl=zh-cn
根据Android开发者官网的文档,Jetpack Compose中可组合项的生命周期与传统的View系统有很大不同。它更关注组合的创建、重组和最终离开组合的过程。
下面结合文档内容,为你梳理Compose生命周期的核心知识点。
目录
🌳 生命周期核心:组合与重组
Compose的生命周期围绕“组合”展开。组合是界面可组合项的树形结构。
- 初始组合:当Compose首次运行可组合项时,会通过执行代码来生成组合。
- 重组:当应用的状态(
State<T>对象)发生变化时,Compose会智能地重新执行那些受影响的、读取了该状态的可组合项,以更新组合。重组是更新界面的唯一方式。
🆔 身份识别:调用点与键 (Key)
在组合中,每个可组合项的实例是通过其调用点来唯一标识的。
-
调用点:即源代码中调用可组合函数的位置。即使调用同一个函数,不同位置的调用也会在组合中创建不同的实例。
-
动态列表的问题:在循环(如
for循环)中调用可组合项时,Compose除了调用点,还会使用执行顺序来区分实例。如果列表顺序改变(增删、排序),Compose可能会错误地将实例与新的数据关联,导致不必要的重组。 -
使用
key解决:为了将实例的身份与其数据(如ID)绑定,可以使用key可组合项包裹代码块。kotlin
key(movie.id) { // 使用唯一ID作为key MovieOverview(movie) }这样,即使列表顺序变化,Compose也能识别出哪个实例对应哪个
movie,从而重用已有的实例,避免不必要的重组和副作用重启。像LazyColumn这样的组件也内置了对key的支持。
⏭️ 智能重组与稳定性
为了提升性能,Compose会在重组时尽可能跳过输入参数未发生变化的可组合项。
- 跳过的条件:如果可组合项的所有输入(参数)都是稳定的,并且自上次组合后未发生变化,Compose就可以安全地跳过它的执行。(UI会正常展示。跳过执行指的是跳过可组合函数的代码块,但不会跳过它在UI树中的存在。)
- 稳定类型:一个类型被认为是稳定的,如果:
- 对于相同的两个实例,
equals的结果总是相同。 - 当类型的任何公共属性发生变化时,Compose能收到通知。
- 所有公共属性的类型也都是稳定的。
- 对于相同的两个实例,
- 常见的稳定类型:
- 所有基本类型(
Boolean、Int、Float等) String- Lambda表达式
MutableState(虽然可变,但Compose会跟踪其.value的变化)
- 所有基本类型(
@Stable注解:对于接口或你认为稳定但Compose无法自动推断的类型(例如,一个所有属性都是val且不可变的数据类),可以使用@Stable注解来标记,告诉Compose将其视为稳定类型,从而启用跳过优化。
💡 生命周期相关的注意事项
- 副作用与身份:将副作用(如
LaunchedEffect、remember)与可组合项关联时,其键(key)通常依赖于可组合项的身份。如果因列表未使用key而导致身份错乱,副作用可能会在不应重启时被取消和重启,引发问题。 - 实例的生命周期:组合中,一个可组合项的实例从首次调用开始存在,直到它因条件不再被调用(如
if条件为false)或从列表中被移除时结束。
📌 总结要点
| 概念 | 说明 |
|---|---|
| 组合 | 描述界面的可组合项树结构。 |
| 重组 | 响应状态变化,智能地重新执行受影响的可组合项以更新界面。 |
| 调用点 | 源代码中调用可组合项的位置,用于在组合中区分实例。 |
key |
在动态列表等场景中,为可组合项实例提供稳定身份标识,避免不必要的重组。 |
| 稳定性 | 类型的一种属性,稳定类型有助于Compose在重组时安全地跳过执行。 |
@Stable |
用于标记类型为稳定,以启用跳过优化。 |
0 条评论