Compose 编译器在编译期对函数参数进行 稳定性分析,决定是否需要跳过重组。核心规则:
✅ 稳定类型(Stable):基本类型、String、函数类型、以及所有属性都是稳定的 data class。
❌ 不稳定类型(Unstable):接口、可变集合、var 属性、MutableState 包装不当等。
| 稳定性类别 | 编译器行为 | 示例 |
|---|---|---|
| 稳定 (Stable) | 允许智能重组,参数不变时跳过 | Int, String, data class 全val |
| 不稳定 (Unstable) | 每次重组都重新执行,可能卡顿 | List<String>, interface, var 字段 |
| 不可变 (Immutable) | 编译器信任其永不改变,最强优化 | String, Int, 枚举 |
推断流程:编译器扫描 Composable 函数参数,检查每个参数类型是否满足稳定条件。若所有参数稳定,则函数可“跳过重组”;否则每次状态变化都会强制重组。
fun MyComposable(list: List<String>) 因为 List 是接口。MutableList、ArrayList 等。val items = mutableListOf("a")data class User(var name: String) → 不稳定。object 但内部有可变状态。| 模式 | 稳定性 | 重组开销 |
|---|---|---|
data class User(val name: String) | 稳定 | 低 (可跳过) |
data class User(var name: String) | 不稳定 | 高 (每次重组) |
List<String> (接口) | 不稳定 | 高 |
ImmutableList<String> (Kotlinx) | 稳定 | 低 |
在 build.gradle.kts 中启用 Compose 编译器报告,生成 稳定性推断报告:
// 模块级 build.gradle.kts
composeCompiler {
reportsDestination = layout.buildDirectory.dir("compose-reports")
metricsDestination = layout.buildDirectory.dir("compose-metrics")
}
运行 Gradle 任务后,在 build/compose-reports 下生成 *-classes.txt 和 *-composables.txt。
// composables.txt 片段
restartable skippable fun MyScreen(
stable user: User
unstable list: List<String>
unstable onClick: Function0<Unit>
)
// classes.txt 片段
unstable class User {
unstable var name: String
}
stable class Product {
stable val id: Int
stable val title: String
}
关键字段:restartable(可重启)、skippable(可跳过)、stable / unstable。若函数标记为 skippable 且参数稳定,则重组时可跳过。
@Stable 或 @Immutable 注解标记自定义类(仅当真的不可变时)。kotlinx.collections.immutable 替代可变集合。val,避免 var。@Stable 标记接口。// 稳定化示例
@Immutable
data class Product(
val id: Int,
val name: String,
val tags: ImmutableList<String> // 稳定集合
)
@Composable
fun ProductCard(product: Product) { // 编译器推断稳定 → skippable
// ...
}