Skip to content

编译器指标 (Compiler Metrics)

源:Compose 编译器指标

你是否遇到过这种困惑:明明使用了 remember,为什么性能还是很差?为什么某些 Composable 无法跳过重组?

不要猜!让 Compose 编译器直接告诉你答案。

1. 启用指标报告

在你的模块级 build.gradle.kts 中添加编译器参数:

kotlin
android {
    // ...
}

// 在 android 块之外配置
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
    compilerOptions {
        freeCompilerArgs.addAll(
            "-P",
            "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.layout.buildDirectory.get().asFile.absolutePath}/compose_metrics",
            "-P",
            "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.layout.buildDirectory.get().asFile.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 认为以下类型是稳定的:

  1. 所有基本类型 (Int, String, Float...)
  2. 函数类型 (Lambda)
  3. 标记了 @Stable@Immutable 的类
  4. 所有属性都是 val 且属性类型也是 Stable 的类