诊断稳定性问题

如果您遇到由于不必要的或过度重新组合而导致的性能问题,则应调试应用的稳定性。本指南概述了几种执行此操作的方法。

布局检查器

Android Studio 中的布局检查器可让您查看哪些可组合项在您的应用中正在重新组合。它显示了 Compose 重组或跳过组件的次数。

Recomposition and skips counts in the Layout Inspector

Compose 编译器报告

Compose 编译器可以输出其稳定性推断的结果以供检查。使用此输出,您可以确定哪些可组合项可跳过,哪些不可跳过。以下小节总结了如何使用这些报告,但有关更详细的信息,请参阅技术文档

设置

Compose 编译器报告默认情况下未启用。您可以使用编译器标志激活它们。确切的设置取决于您的项目,但对于使用Compose 编译器 Gradle 插件的项目,您可以在每个模块的build.gradle文件中添加以下内容。

  android { ... }

  composeCompiler {
    reportsDestination = layout.buildDirectory.dir("compose_compiler")
    metricsDestination = layout.buildDirectory.dir("compose_compiler")
  }

现在,在构建您的项目时将生成 Compose 编译器报告。

示例输出

reportsDestination输出三个文件。以下是来自JetSnack的示例输出。

  • <modulename>-classes.txt有关此模块中类的稳定性的报告。示例
  • <modulename>-composables.txt有关模块中可组合项的可重启性和可跳过性的报告。示例
  • <modulename>-composables.csv可组合项报告的CSV版本,您可以将其导入电子表格或使用脚本进行处理。示例

可组合项报告

composables.txt文件详细介绍了给定模块的每个可组合函数,包括其参数的稳定性,以及它们是否可重启或可跳过。以下是来自JetSnack的假设示例

restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun SnackCollection(
  stable snackCollection: SnackCollection
  stable onSnackClick: Function1<Long, Unit>
  stable modifier: Modifier? = @static Companion
  stable index: Int = @static 0
  stable highlight: Boolean = @static true
)

SnackCollection可组合项完全可重启、可跳过且稳定。这通常是首选,尽管并非强制要求。

另一方面,让我们看一下另一个例子。

restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
  stable index: Int
  unstable snacks: List<Snack>
  stable onSnackClick: Function1<Long, Unit>
  stable modifier: Modifier? = @static Companion
)

HighlightedSnacks可组合项不可跳过。Compose 在重新组合期间永远不会跳过它。即使其参数都没有更改,也会发生这种情况。原因是该unstable参数,snacks

类报告

文件classes.txt包含有关给定模块中类的类似报告。以下代码段是类Snack的输出

unstable class Snack {
  stable val id: Long
  stable val name: String
  stable val imageUrl: String
  stable val price: Long
  stable val tagline: String
  unstable val tags: Set<String>
  <runtime stability> = Unstable
}

作为参考,以下是Snack的定义

data class Snack(
    val id: Long,
    val name: String,
    val imageUrl: String,
    val price: Long,
    val tagline: String = "",
    val tags: Set<String> = emptySet()
)

Compose 编译器已将Snack标记为不稳定。这是因为tags参数的类型为Set<String>。这是一个不可变类型,因为它不是MutableSet。但是,诸如Set, ListMap之类的标准集合类最终是接口。因此,底层实现可能仍然是可变的。

例如,您可以编写val set: Set<String> = mutableSetOf("foo")。变量是常量,其声明的类型不可变,但其实现仍然是可变的。Compose 编译器无法确定此类的不可变性,因为它只看到声明的类型。因此,它将tags标记为不稳定。