编译器指标 (Compiler Metrics)
你是否遇到过这种困惑:明明使用了 remember,为什么性能还是很差?为什么某些 Composable 无法跳过重组?
不要猜!让 Compose 编译器直接告诉你答案。
1. 启用指标报告
在你的模块级 build.gradle.kts 中添加编译器参数:
kotlin
android {
// ...
kotlinOptions {
freeCompilerArgs += listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.buildDir.absolutePath}/compose_metrics",
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.buildDir.absolutePath}/compose_metrics"
)
}
}重新构建项目 (./gradlew assembleRelease) 后,你会在 build/compose_metrics 目录下看到 4 个文件。
2. 解读报告
最重要的文件是 *-composables.txt。
text
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun Greeting(
stable name: String
)关键词解析
| 关键词 | 含义 | 评价 |
|---|---|---|
| restartable | 该函数可以作为重组的入口点(Scope)。 | 正常 |
| skippable | 如果参数没变,Compose 可以跳过执行。 | 非常棒 (目标) |
| stable | 参数类型是稳定的。 | 必须 |
| unstable | 参数类型是不稳定的。 | 警告 (性能杀手) |
如果你的函数包含 unstable 参数,它就永远不会是 skippable 的。每次父组件重组,它都会跟着重组。
3. 修复 Unstable
案例分析
text
restartable fun ContactRow(
unstable user: User // <--- 问题出在这里
)因为 User 类可能包含 var 属性,或者它来自第三方库(Compose 编译器无法推断其稳定性)。
解决方案
1. 添加 @Stable 注解
如果你能保证该类是不可变的,或者其变化能通过 State 机制通知 Compose,请手动标记。
kotlin
@Stable
data class User(val name: String)2. 启用强跳过模式 (Strong Skipping)
这是 Compose 1.5.4+ 的新特性,它不再通过类型稳定性来判断,而是通过比较对象实例(equals)来决定是否跳过。
3. 使用稳定集合
使用 kotlinx.collections.immutable.PersistentList 替代 List。
4. 稳定性推断规则
Compose 认为以下类型是稳定的:
- 所有基本类型 (Int, String, Float...)
- 函数类型 (Lambda)
- 标记了
@Stable或@Immutable的类 - 所有属性都是
val且属性类型也是 Stable 的类