本文译自「Compose Stability Analyzer: Real-Time Stability Insights for Jetpack Compose」,原文链接https://medium.com/proandroiddev/compose-stability-analyzer-real-time-stability-insights-for-jetpack-compose-1399924a0a64,由Jaewoong Eum发布于2025年11月10日。
Jetpack Compose 以其声明式编程范式革新了 Android UI 开发,但这种简洁性背后却隐藏着复杂性:理解重组合行为。当一个可组合元素不必要地进行重组合时,就会造成性能损失,CPU 周期会浪费在重新渲染实际上并未改变的 UI 上。挑战不仅在于识别这些问题,更在于理解它们发生的原因。
Compose 编译器一直在后台执行稳定性分析,确定哪些可组合元素在输入未发生变化时可以跳过重组合。但这种分析是在编译时静默进行的,开发者无法得知他们的可组合元素是否得到了优化。你可能编写出看似完美稳定的代码,但之后却发现类中一个 var 属性就足以导致整个代码不稳定,并波及整个 UI 树。
Compose Stability Analyzer 将这种隐藏的分析揭示出来。它是一套全面的工具集,可在 IDE 中提供实时可视化反馈,通过注解进行运行时代码重组追踪,并在 CI 流水线中进行稳定性验证。无需等到性能问题在生产环境中出现,你就能在编码过程中获得即时反馈,使稳定性分析自然而然地融入你的开发工作流程。
本文将探讨 Compose 稳定性分析器的工作原理,包括:IntelliJ 插件(为你的 IDE 提供可视化的稳定性指示器)、编译器插件(启用运行时重组跟踪)以及稳定性验证系统(防止回归问题影响生产环境)。
理解稳定性问题:为什么可组合函数会重组
在深入工具之前,值得了解 Compose 编译器实际上分析的内容。编译器会对每个可组合函数执行稳定性推断,回答两个问题:
1. 这个可组合函数可以跳过吗?
当编译器能够证明使用相同的输入重新组合该函数会产生相同的结果时,该可组合函数就是可跳过的。如果所有参数都是稳定的并且没有发生变化,可组合函数可以完全跳过重新组合,这是一个显著的性能优化。
2. 该可组合项是否可重启?
当一个可组合项可以独立重新组合而无需重新组合其父项时,该可组合项是可重启的。这使得重新组合更加细粒度。大多数可组合项都是可重启的,但带有某些修饰符的可组合项可能不是。
这里的关键概念是参数稳定性。当 Compose 编译器能够可靠地检测到参数值是否发生变化时,该参数是稳定的。规则非常复杂,如果你想深入了解这些规则,可以参考稳定性研究Compose 稳定性推断。
在 Android Studio 中进行可视化稳定性分析
Compose Stability Analyzer IntelliJ 插件可将稳定性分析直接集成到 Android Studio 和 IntelliJ IDEA 中,在你编写代码时提供四层可视化反馈。
安装和设置
安装插件非常简单:
打开 Android Studio → 设置 → 插件 → 应用市场。
搜索“Compose Stability Analyzer”。
点击 安装 并重启 IDE。

安装完成后,插件会立即开始分析你的代码。无需任何配置,它可与任何 Compose 项目开箱即用。
边栏图标:即时视觉反馈
最直观的功能是边栏图标,即出现在可组合函数左侧边栏的彩色圆点:

绿点:此可组合函数可跳过。所有参数均稳定,编译器可以优化重新组合。
黄点:此可组合函数可重启,但不可跳过。它会在其父函数重新组合时重新组合。
红点:此可组合函数的参数不稳定,无法进行优化。
这种即时视觉反馈是快速发现 Jetpack Compose 性能问题的最佳方法。只需快速浏览左侧边栏,即可了解哪些可组合函数需要关注。如果屏幕上布满红点,则说明需要进行一些优化工作。
边栏图标的计算基于 Compose 编译器执行的相同稳定性分析。该插件会接入编译器的分析阶段并提取稳定性信息,然后在编辑器中以可视化的方式呈现。
但请注意,目前强跳过模式默认大多已启用,因此所有可组合函数默认都可以跳过。你可以在插件配置中启用或禁用强跳过模式检查(工具 > Compose 稳定性分析器),该功能自 0.5.0 版本起也默认启用。如果你希望更加关注稳定性问题,可以根据实际情况将其关闭。

悬停提示:了解原因
边栏图标告诉你哪里出了问题,而悬停提示则告诉你为什么。当你将鼠标悬停在可组合函数名称上时,会显示详细的提示信息:

提示信息显示:
可组合函数是否可跳过和可重启
稳定参数与不稳定参数的总数
每个参数的详细稳定性信息
接收器稳定性(针对扩展函数)
这种细致的反馈对于调试至关重要。你无需猜测哪个参数导致了不稳定,而是可以准确地看到哪些参数存在问题。
内联参数提示:精细化可见性
工具提示会在鼠标悬停时提供详细信息,而内联参数提示则无需任何交互即可提供持续可见性:

函数签名中每个参数类型旁边都会显示小徽章,指示该参数是稳定还是不稳定。这是最详细的反馈级别;每个参数的稳定性一目了然。
对于参数众多的函数,这有助于你快速浏览并识别有问题的参数,而无需打开工具提示。颜色编码与稳定性状态相对应:
绿色徽章:参数稳定
红色徽章:参数不稳定
黄色徽章:稳定性将在运行时决定(因此可能稳定也可能不稳定)
代码检查:自动建议
第四层反馈是主动代码检查。当插件检测到不稳定的组合体时,它可以:
用警告下划线突出显示问题。
通过 Alt+Enter 菜单提供快速修复建议。
提供添加注解(例如
@TraceRecomposition)以进行调试。提供抑制选项(如果不稳定是故意的)。

插件在此开始主动出击。它不仅会指出问题,还会提供解决方案。在不稳定的组合体上按下 Alt+Enter,你可能会看到如下选项:
添加
@TraceRecomposition以监控重新组合。使用
@Stable注解进行标记(请谨慎使用)。抑制此函数的稳定性警告。
稳定性浏览器:包级分析
除了单个函数分析之外,稳定性浏览器还提供整个代码库稳定性的概览:

启用方法:
安装 Compose Stability Analyzer Gradle 插件(下一节将介绍)。
转到“视图”→“工具窗口”→“Compose Stability Analyzer”。
构建项目并单击刷新按钮。
浏览器以树状视图显示包结构,每个可组合函数都带有其稳定性状态的注解。你可以快速深入查找整个代码库中不稳定的函数,从而轻松地确定优化工作的优先级。
这在大型项目中尤其有用,因为手动检查每个可组合组件是不切实际的。该工具会为你的应用程序提供一份稳定性“成绩单”,显示哪些包存在最多的稳定性问题。
自定义配置
该插件具有高度可定制性。你可以调整颜色、启用或禁用特定的视觉指示器,并配置分析行为以满足你的偏好。
前往“设置”→“工具”→“Compose Stability Analyzer”(组合稳定性分析器)访问配置选项:

你可以:
更改边栏图标颜色以匹配你的 IDE 主题
分别启用或禁用内联提示、警告和边栏图标
配置强跳过模式分析
添加忽略类型模式以从分析中排除某些类
在测试源集中启用分析
设置自定义稳定性配置文件
这种灵活性确保插件能够自然地融入你现有的工作流程,无论你偏好最小的视觉干扰还是最大的信息密度。
Gradle 插件:运行时重组追踪
IntelliJ 插件提供编译时可见性,而 Gradle 插件则支持运行时分析,能够精确追踪可组合组件在运行中的重组时间和原因。这是通过 @TraceRecomposition 注解实现的,该注解是一个编译器插件,它会在可组合组件中添加日志代码。
安装和设置
将以下依赖项添加到 libs.versions.toml 文件中:
1
| |
接下来,将插件应用到根目录下的 build.gradle.kts 文件中,如下所示:
1
| |
完成!该插件会自动将编译器插件应用到项目中的所有 Kotlin 编译任务。基本用法无需额外配置。
Kotlin 版本兼容性
该插件与 Kotlin 编译器紧密耦合,因此版本一致性至关重要。截至撰写本文时,你至少应使用 Kotlin 2.2.21 版本。使用不匹配的版本可能会导致编译错误。请始终使用与你的稳定性分析器版本完全匹配的 Kotlin 版本。你可以参考 Kotlin 版本映射表(https://github.com/skydoves/compose-stability-analyzer?tab=readme-ov-file#kotlin-version-mapping%EF%BC%89%E8%8E%B7%E5%8F%96%E7%9B%B8%E5%85%B3%E4%BF%A1%E6%81%AF%E3%80%82
@TraceRecomposition 注解
安装插件后,你可以使用 @TraceRecomposition 注解任何可组合组件,以跟踪其重组行为:
1 2 3 4 5 6 7 8 9 10 11 | |
当此可组合组件重组时,你将在 Logcat 中看到详细的日志:
1 2 3 4 5 6 | |
日志显示:
重组次数:此实例已重组的次数
参数稳定性:每个参数是稳定还是不稳定
变更检测:哪些参数发生了更改,显示新旧值
身份跟踪:每个参数值的哈希码
这些细粒度的信息对于调试至关重要。你可以准确地看到是哪个参数的更改触发了重组,从而帮助你了解应用程序的重组模式。
使用标签参数进行过滤
对于包含大量跟踪可组合组件的大型应用程序,日志可能会变得非常庞大。 tag 参数可以帮助你组织和筛选日志:
1 2 3 4 5 6 7 8 9 10 11 | |
现在日志包含以下标签:
1 2 | |
你可以筛选 Logcat 以仅显示特定标签:
按
tag: product-list筛选,仅查看与产品相关的重组日志。按
tag: user-profile筛选,仅查看与用户个人资料相关的重组日志。
这在与自定义日志记录器(将在下文介绍)结合使用时尤其有用,因为你可能只想将某些标签发送到分析服务。
设置阈值以减少噪音
大多数可组合组件在初始设置期间会重新组合 1-2 次,这是预期行为,并非性能问题。threshold 参数可以过滤掉这些噪音:
1 2 3 4 5 | |
这样可以将注意力集中在真正的问题上:用户交互期间不断重新组合的可组合组件,而不仅仅是初始设置。
一个实际用例:设置一个较高的阈值,并在超过该阈值时发送分析事件:
1 2 3 4 5 | |
然后在你的自定义日志记录器(参见下一节)中,你可以在超过阈值时发送 Firebase 事件,从而监控生产环境中的性能问题。
配置日志系统
默认情况下,@TraceRecomposition 不会记录任何日志,你需要在 Application 类中启用日志记录:
1 2 3 4 5 6 7 8 | |
这一点非常重要,如果你没有自定义日志记录器,务必使用 **BuildConfig.DEBUG** 包裹,以避免生产构建中潜在的安全问题。
自定义日志记录器:Logcat 之外的选择 默认日志记录器使用 Logcat,但你可以提供自定义实现,将日志发送到你想要的任何位置:
1 2 3 4 5 6 7 8 9 10 11 12 | |
因此,你甚至可以根据调试模式或发布模式设置不同的日志记录器。RecompositionEvent 包含:
composableName:函数名称。tag:来自@TraceRecomposition的标签。recompositionCount:重新组合的次数。parameterChanges:包含稳定性信息的参数变更列表。unstableParameters:不稳定参数名称列表。
这支持强大的监控模式。你可以:
针对过度重组的组合对象发送分析事件
在生产环境中跟踪性能指标(并采取适当的隐私保护措施)
构建显示重组模式的自定义仪表板
在测试环境中出现性能下降时发出警报
以下是一个使用标签过滤日志内容的更贴近实际的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
理解日志
让我们一起来了解如何解读日志。请看以下示例:
1 2 3 | |
这意味着:
这是此
UserCard实例的首次重组。两个参数都稳定。
这是初始重组的预期行为。
1 2 3 | |
这意味着:
第二次重组。
user参数已更改(新实例)。onClick保持不变(相同的 lambda 实例)。这是正常现象,参数已更改,因此需要进行重组。
1 2 3 | |
这意味着:
第三次重组。
user参数不稳定(可能具有var属性)。即使
user没有更改,此可组合对象也会在每次父级重组时重新组合。需要采取的措施:将
MutableUser类修复为不可变。
稳定性验证:防止 CI 中的性能退化
Compose 稳定性分析器最强大的功能并非可视化反馈或运行时跟踪,而是防止稳定性退化影响生产环境。稳定性验证系统的作用类似于 git diff,用于检查可组合组件的稳定性,如果稳定性下降,则 CI 构建失败。
问题:静默的性能退化
想象一下这样的场景:你花了数周时间优化你的应用。每个可组合组件都稳定、可跳过且运行速度快。然后,一位同事无意中修改了一个数据类:
1 2 3 4 5 | |
这一简单的更改会波及整个 UI 树。数十个原本可跳过的可组合组件变得不可跳过。性能退化了,但代码审查却未能发现,也没有任何明显的迹象表明出了问题。
稳定性验证可以防止这种情况发生。它会跟踪你的可组合组件的稳定性随时间的变化,并在稳定性下降时自动构建失败,强制在合并之前解决问题。
工作原理:稳定性快照
验证系统通过两个 Gradle 任务运行:
**stabilityDump**:创建一个包含所有可组合组件稳定性状态的.stability文件。**stabilityCheck**:将当前代码与基线进行比较,如果稳定性下降则构建失败。
可以这样理解:
stabilityDump= “保存当前状态”stabilityCheck= “自上次保存以来是否有任何更改?”
步骤 1:创建基线
编译项目后,运行:
1 2 | |
这将生成 app/stability/app.stability 文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
此文件易于阅读,并准确显示了编译器对每个可组合组件的判断结果。它是应用程序稳定性状态的完整快照。
将此文件提交到 Git:
1 2 3 | |
现在,团队中的每个人都拥有相同的基线。
步骤 2:检查回归问题
在你的 CI 流水线中运行:
1 2 | |
如果没有任何变化,任务成功:
1
| |
如果稳定性出现回归,任务失败:
1 2 3 4 5 6 7 | |
构建失败,在问题修复或明确接受回归之前,拉取请求将无法合并。
检测到的变更类型
验证器会检测到四种类型的变更:

这种全面的跟踪机制确保任何稳定性变更都清晰可见,并需要进行相应的决策。
CI/CD 集成
将稳定性验证添加到你的 GitHub Actions 工作流:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
现在,每个拉取请求都会自动进行检查。如果稳定性下降,则拉取请求将无法合并。
配置选项
你可以自定义要跟踪的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
这对于排除不需要稳定性跟踪的代码非常有用,例如预览组合或调试屏幕。
排除特定组合
使用 @IgnoreStabilityReport 从验证中排除单个组合:
1 2 3 4 5 6 | |
预览组合不会出现在生产版本中,因此它们的稳定性无关紧要。排除它们可以减少稳定性报告中的噪音。
多模块项目
对于包含多个模块的项目,每个模块都会有自己的 .stability 文件:
1 2 3 4 | |
在根目录运行 stabilityCheck 来检查所有模块:
1
| |
或者检查单个模块:
1
| |
接受有意为之的回归
有时稳定性回归是有意为之的,例如你正在重构代码并暂时接受较低的稳定性。在这种情况下,请更新基线:
1 2 3 4 | |
这会在 Git 历史记录中创建一个已记录的决策。回归不再是默默进行的,而是明确且可跟踪的。
性能考量和最佳实践
虽然这些工具功能强大,但仍有一些性能特性和最佳实践需要注意。有人问我是否需要让每个类型都稳定,答案绝对是“不需要”。
由于现在有了强跳过模式,每个可组合函数都可以跳过,这本身就能优化稳定性。即使这个插件可能会提示“不稳定”或“运行时稳定性”,但你实际上并不需要为每个可组合函数都进行修复。我们来看一个简单的例子。

如果你查看 compose-material3 库中的 Icon 可组合函数,这个插件会提示它不稳定,因为它包含运行时参数。但是,painter 参数通常是通过 painterResource 函数初始化的,如下所示:
1 2 | |
如果你查看 painterResource 的内部逻辑,你会发现它本质上是稳定的。它内部使用 remember 将值缓存到内存中,所以你可以把它看作是一个小小的权衡:“我会用一点内存来存储这个不稳定的实例,这样我就不必触发不必要的重新组合。”

关于不可变集合还有一个常见的误解——认为仅仅使用 ImmutableList 而不是普通的 List 就能提升性能。 并非总是如此。
不妨这样想:如果你有一个包含 1000 个大型对象的列表,然后你将其转换为不可变列表,那么你的可组合组件就变得可以忽略了。但是,每次重新组合时,Compose 都会对列表中的每个元素运行 equals() 函数,以检查新实例是否与之前的实例匹配。在某些情况下,这实际上会比重新渲染一个只显示其中五个元素的轻量级 UI 更影响性能。
因此,稳定性会根据具体情况产生截然不同的影响,试图让整个 UI 保持稳定通常是不必要的,也是徒劳的。我希望这个插件不会加重你对稳定性的担忧,而是能够帮助你更有效地调试实际的性能问题,并做出更明智、更数据驱动的决策,而无需过度考虑稳定性。
结论
在本文中,我们探索了 Compose 稳定性分析器 (Compose Stability Analyzer) (https://github.com/skydoves/compose-stability-analyzer),了解了它如何通过三个互补的工具将 Compose 隐藏的稳定性分析可视化:IntelliJ 插件用于在开发过程中提供可视化反馈,Gradle 插件用于运行时重组追踪,以及稳定性验证系统用于防止持续集成 (CI) 中的回归。
IntelliJ 插件将稳定性从一个不可见的编译时概念转化为可感知的事物,通过边栏图标、工具提示和内联提示,使稳定性问题一目了然。@TraceRecomposition 注解弥合了编译时分析和运行时行为之间的鸿沟,让你可以准确地了解可组合组件何时以及为何重新组合。稳定性验证系统则起到安全网的作用,确保你精心设计的优化不会随着代码库的演进而悄然失效。
这些工具共同作用,使稳定性分析成为你开发工作流程中自然而然的一部分。你无需等待性能问题显现,即可在编码过程中立即发现它们。你无需猜测哪个参数导致了重新组合——日志会准确地告诉你哪些参数发生了变化。你也无需手动审查每个 PR 是否存在稳定性回归,CI 流水线会自动完成这项工作。
理解稳定性是编写高性能 Compose 应用程序的基础。借助 Compose 稳定性分析器,这种理解变得轻松、直观、即时且有效。
祝你编码愉快!