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 los recuentos de cuántas veces Compose recompuso o omitió 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. En las siguientes subsecciones, se resume 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")
  }

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

Ejemplo de resultado:

El programa reportsDestination genera tres archivos. A continuación, se muestran ejemplos de resultados de JetSnack.

  • <modulename>-classes.txt: Es un informe sobre la estabilidad de las clases en este módulo. Muestra.
  • <modulename>-composables.txt: Es un informe sobre qué tan reiniciables y omitibles son los elementos componibles en el módulo. Muestra.
  • <modulename>-composables.csv: 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. Muestra

Informe de elementos componibles

El archivo composables.txt detalla cada función de componibilidad para el módulo determinado, incluida la estabilidad de sus parámetros y si se pueden reiniciar o omitir. A continuación, se muestra 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 SnackCollection componible es completamente reiniciable, omitible y estable. En general, esta opción es preferible, aunque no es obligatoria.

Por otro lado, veamos 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 HighlightedSnacks componible no se puede omitir. Compose nunca lo omite durante la recomposición. Esto ocurre incluso si no cambió ninguno de sus parámetros. El motivo es el parámetro unstable, snacks.

Informe de clases

El archivo classes.txt contiene un informe similar sobre las clases del 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, a continuación, se incluye 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 del parámetro tags 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 sigue siendo mutable. El compilador de Compose no puede garantizar la inmutabilidad de esta clase, ya que solo ve el tipo declarado. Por lo tanto, marca tags como inestable.