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树中的存在。)
  • 稳定类型:一个类型被认为是稳定的,如果:
    1. 对于相同的两个实例,equals的结果总是相同。
    2. 当类型的任何公共属性发生变化时,Compose能收到通知。
    3. 所有公共属性的类型也都是稳定的。
  • 常见的稳定类型
    • 所有基本类型(BooleanIntFloat等)
    • String
    • Lambda表达式
    • MutableState(虽然可变,但Compose会跟踪其.value的变化)
  • @Stable注解:对于接口或你认为稳定但Compose无法自动推断的类型(例如,一个所有属性都是val且不可变的数据类),可以使用@Stable注解来标记,告诉Compose将其视为稳定类型,从而启用跳过优化。

💡 生命周期相关的注意事项

  • 副作用与身份:将副作用(如LaunchedEffectremember)与可组合项关联时,其键(key)通常依赖于可组合项的身份。如果因列表未使用key而导致身份错乱,副作用可能会在不应重启时被取消和重启,引发问题。
  • 实例的生命周期:组合中,一个可组合项的实例从首次调用开始存在,直到它因条件不再被调用(如if条件为false)或从列表中被移除时结束。

📌 总结要点

概念 说明
组合 描述界面的可组合项树结构。
重组 响应状态变化,智能地重新执行受影响的可组合项以更新界面。
调用点 源代码中调用可组合项的位置,用于在组合中区分实例。
key 在动态列表等场景中,为可组合项实例提供稳定身份标识,避免不必要的重组。
稳定性 类型的一种属性,稳定类型有助于Compose在重组时安全地跳过执行。
@Stable 用于标记类型为稳定,以启用跳过优化。

0 条评论

发表回复

您的电子邮箱地址不会被公开。