compose中的@Stable概念和用法

这个问题问得非常专业 ,而且你问的点已经不是"会不会用 Compose",而是Compose 编译器和运行时是怎么工作的 这一层了 👍

我会按 "你脑子里应该形成的模型" 来讲,而不是背概念。


一句话先给结论(先记住)

@Stable 不是告诉 Compose「这个类不会变」,
而是告诉 Compose「这个类的变化是可预测的」

这是 90% 的人理解错的地方。


一、Compose 到底在怕什么?

Compose 最怕的是

❌ 无法判断一个对象"值有没有变"

因为:

  • Compose 靠状态变化触发重组
  • 如果它不知道一个参数"有没有变"
  • 就只能 保守地重组

二、Compose 判断「是否变化」的规则(非常重要)

默认情况下,Compose 对参数有三种认知:

类型 Compose 如何判断
基本类型 / String 直接 ==
@Immutable 值完全不可变
普通 class 不知道,默认当作会变

👉 普通 class = 不可信


三、那 @Stable 到底是什么意思?

官方定义(翻译成人话):

@Stable 表示:

1️⃣ 对象的 equals() 是稳定的

2️⃣ 公共属性的变化是可追踪的

3️⃣ 如果属性没变,对象行为不会变

⚠️ 注意:
不是说它不会变,而是"变得可追踪"


四、Compose 知道标了 @Stable 后,会干什么?

这是最关心的点 👇

Compose 编译器 + Runtime 会做三件关键的事


✅ 1️⃣ 参数比较策略改变(核心)

kotlin 复制代码
@Composable
fun UserCard(user: User) { ... }
❌ 没有 @Stable
text 复制代码
User 是普通类 → 认为可能变化
→ 父重组时,UserCard 一定重组
✅ 有 @Stable
text 复制代码
Compose 只在"User 的可观察属性变了"时才重组

📌 直接减少重组次数


✅ 2️⃣ 跳过(Skip)Composable 调用

Compose 有一个非常重要的优化:skip

kotlin 复制代码
if (参数没变) {
    跳过这个 Composable
}

@Stable允许 skip 的前提条件


✅ 3️⃣ 推断 State 依赖关系

@Stable 类中:

kotlin 复制代码
@Stable
class UiState(
    val title: String,
    val count: Int
)

Compose 能推断:

  • title / count 没变
  • UI 输出一定没变
  • 👉 不需要重组

五、一个非常直观的对比例子(一看就懂)

❌ 不加 @Stable(性能差)

kotlin 复制代码
class CounterState(var count: Int)

@Composable
fun Counter(state: CounterState) {
    Text("count=${state.count}")
}

即使 count 没变,只要父重组:

👉 Counter() 必定重组


✅ 加 @Stable(性能好)

kotlin 复制代码
@Stable
class CounterState(var count: Int)

@Composable
fun Counter(state: CounterState) {
    Text("count=${state.count}")
}

现在:

  • count 没变 → 不重组
  • count 变了 → 精确重组

六、那和 @Immutable 有什么区别?

注解 含义
@Immutable 永远不会变(val + 不可变)
@Stable 可以变,但变化可追踪

用错后果:

  • 把可变对象标成 @Immutable → ❌ BUG
  • 把随意变的对象标成 @Stable → ❌ UI 不更新

七、为什么 MVI + Compose 项目里经常看到 @Stable?

因为:

kotlin 复制代码
data class UiState(...)

或者:

kotlin 复制代码
class UiState(
    val list: List<Item>,
    val loading: Boolean
)
  • 这些 经常作为 Composable 参数
  • 频繁参与重组判断
  • @Stable = 减少整树重组

👉 在复杂页面上,差距非常明显


八、Compose 并不会"自动帮你标"

Compose 宁可慢,也不冒险

"我不知道你这个对象会不会偷偷变"

所以你需要 显式告诉它


九、什么时候该用 @Stable?(工程规则)

✅ 适合用的场景

  • UI State 类
  • ViewModel 暴露给 UI 的对象
  • 长生命周期、频繁传递的参数
  • 内部字段受控(只在 VM 改)

❌ 不该用的场景

  • mutableList / mutableMap 暴露在外
  • 随意 set 的 public var
  • 非 UI 层对象
  • 不确定变化来源的类

十、可以用一句话向别人解释 @Stable(面试级)

@Stable 告诉 Compose:
这个对象的变化是可预测的,
如果它的可观察属性没变,UI 就不会变。


最后一句实话(非常重要)

@Stable性能承诺 ,不是语法糖。
你对它负责,Compose 信你。

相关推荐
码农搬砖_20208 小时前
【一站式学会compose】 Android UI体系之 Image的使用和介绍
android·image·compose·content·contentscale·scaletype
stevenzqzq1 天前
Compose重组的概念1
命令模式·compose
stevenzqzq1 天前
compose中 DisposableEffect和onDispose
compose
stevenzqzq1 天前
compose中 SideEffect概念以及作用
compose
码农搬砖_20201 天前
【一站式学会compose】 Android UI体系之 Text的使用和介绍
android·compose
stevenzqzq2 天前
Compose基础入门
开发语言·compose
stevenzqzq2 天前
Compose 实战练习
compose
遇见火星5 天前
Docker Compose 实战教程,理解Docker Compose核心概念,学会编写 compose.yml,掌握常用命令!
运维·docker·容器·compose
csdn12259873369 天前
JetPack Compose 入门先搞清楚
android·compose·jetpack