Diagnostica problemas de estabilidad

Si tienes problemas de rendimiento que se deben a una recomposición innecesaria o excesiva, debes depurar la estabilidad de tu app. En esta guía, se describen varios métodos para hacerlo.

Inspector de diseño

El Inspector de diseño de Android Studio te permite ver qué elementos componibles se recomponen en tu app. Muestra la cantidad de veces que Compose recomponía o omitía un componente.

Recuentos de recomposición y omisiones en el Inspector de diseño

Informes del compilador de Compose

El compilador de Compose puede generar los resultados de su inferencia de estabilidad para su inspección. Con este resultado, puedes determinar cuáles de tus elementos componibles se pueden omitir y cuáles no. Las siguientes subsecciones resumen cómo usar estos informes, pero para obtener información más detallada, consulta la documentación técnica.

Configuración

Los informes del compilador de Compose no están habilitados de forma predeterminada. Puedes activarlos con una marca del compilador. La configuración exacta varía según tu proyecto, pero para los proyectos que usan el complemento de Gradle del compilador de Compose, puedes agregar lo siguiente en el archivo build.gradle de cada módulo.

  android { ... }

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

Ahora se generarán informes del compilador de Compose cuando compiles tu proyecto.

Resultado de ejemplo

reportsDestination genera tres archivos. Los siguientes son ejemplos de resultados de JetSnack.

  • <modulename>-classes.txt: Es un informe sobre la estabilidad de las clases en este módulo. Ejemplo.
  • <modulename>-composables.txt: Es un informe sobre qué tan reiniciables y omitibles son los elementos componibles en el módulo. Ejemplo.
  • <modulename>-composables.csv: Es una versión CSV del informe de elementos componibles que puedes importar a una hoja de cálculo o procesar con una secuencia de comandos. Ejemplo

Informe de elementos componibles

El archivo composables.txt detalla cada función componible para el módulo determinado, incluida la estabilidad de sus parámetros y si se pueden reiniciar o omitir. El siguiente es un ejemplo hipotético de 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
)

Este elemento componible SnackCollection es completamente reiniciable, omitible y estable. Por lo general, esto es preferible, aunque no es obligatorio.

Como alternativa, considera otro ejemplo.

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
)

El elemento componible HighlightedSnacks no se puede omitir. Compose nunca lo omite durante la recomposición. Esto ocurre incluso si ninguno de sus parámetros cambió. El motivo es el parámetro unstable, snacks.

Informe de clases

El archivo classes.txt contiene un informe similar sobre las clases en el módulo determinado. El siguiente fragmento es el resultado de la clase 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
}

Como referencia, la siguiente es la definición de Snack:

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

El compilador de Compose marcó Snack como inestable. Esto se debe a que el tipo de el tags parámetro es Set<String>. Este es un tipo inmutable, ya que no es un MutableSet. Sin embargo, las clases de colección estándar, como Set, List y Map, son, en última instancia, interfaces. Por lo tanto, la implementación subyacente aún puede ser mutable.

Por ejemplo, puedes escribir val set: Set<String> = mutableSetOf("foo"). La variable es constante y su tipo declarado no es mutable, pero su implementación aún es mutable. El compilador de Compose no puede estar seguro de la inmutabilidad de esta clase, ya que solo ve el tipo declarado. Por lo tanto, marca tags como inestable.