Se você estiver enfrentando problemas de desempenho resultantes de recomposição desnecessária ou excessiva, depure a estabilidade do app. Este guia descreve vários métodos para fazer isso.
Layout Inspector
O Layout Inspector no Android Studio permite conferir quais elementos combináveis estão sendo recompostos no app. Ele exibe contagens de quantas vezes o Compose recompõe ou ignorou um componente.
Relatórios do compilador do Compose
O compilador do Compose pode gerar os resultados da inferência de estabilidade para inspeção. Usando essa saída, é possível determinar quais dos elementos combináveis são puláveis e quais não são. As subseções a seguir resumem como usar esses relatórios. Para informações mais detalhadas, consulte a documentação técnica.
Configurar
Os relatórios do compilador do compilador não são ativados por padrão. Você pode ativá-los com
uma flag do compilador. A configuração exata varia de acordo com o
projeto. Porém, para a maioria deles, você pode colar o script abaixo no arquivo raiz
build.gradle
.
Groovy
subprojects {
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
kotlinOptions {
if (project.findProperty("composeCompilerReports") == "true") {
freeCompilerArgs += [
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" +
project.buildDir.absolutePath + "/compose_compiler"
]
}
if (project.findProperty("composeCompilerMetrics") == "true") {
freeCompilerArgs += [
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" +
project.buildDir.absolutePath + "/compose_compiler"
]
}
}
}
}
Kotlin
subprojects {
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
kotlinOptions {
if (project.findProperty("composeCompilerReports") == "true") {
freeCompilerArgs += listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.buildDir.absolutePath}/compose_compiler"
)
}
if (project.findProperty("composeCompilerMetrics") == "true") {
freeCompilerArgs += listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.buildDir.absolutePath}/compose_compiler"
)
}
}
}
}
Executar a tarefa
Para depurar a estabilidade dos elementos combináveis, execute a tarefa desta forma:
./gradlew assembleRelease -PcomposeCompilerReports=true
Exemplo de saída
Essa tarefa gera três arquivos. Confira abaixo exemplos de saídas do JetSnack.
<modulename>-classes.txt
:relatório sobre a estabilidade das classes neste módulo. Amostra.<modulename>-composables.txt
:um relatório sobre a capacidade de reiniciar e pulsar os elementos combináveis no módulo. Amostra.<modulename>-composables.csv
:uma versãoCSV
do relatório de elementos combináveis, que pode ser importada para uma planilha ou um processamento usando um script. Exemplo
Relatório de elementos combináveis
O arquivo composables.txt
detalha cada função combinável do módulo
especificado, incluindo a estabilidade dos parâmetros e se eles são
reiniciáveis ou puláveis. Confira a seguir um exemplo hipotético do
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
)
O elemento combinável SnackCollection
é completamente reiniciável, pulável e
estável. Isso geralmente é preferível, embora certamente não seja obrigatório.
Por outro lado, vamos conferir outro exemplo.
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
)
O elemento combinável HighlightedSnacks
não é pulável. O Compose nunca a pula
durante a recomposição. Isso vai acontecer mesmo que nenhum dos parâmetros seja alterado.
O motivo para isso é o parâmetro unstable
, snacks
.
Relatório de turmas
O arquivo classes.txt
contém um relatório semelhante sobre as classes do módulo
em questão. O snippet a seguir é a saída para a classe 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
}
Para referência, esta é a definição 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()
)
O compilador do Compose marcou Snack
como instável. Isso ocorre porque o tipo de
parâmetro tags
é Set<String>
. Esse é um tipo imutável, já que
não é um MutableSet
. No entanto, as classes de coleção padrão, como Set, List
e Map
, são interfaces. Assim, a implementação subjacente ainda pode
ser mutável.
Por exemplo, é possível escrever val set: Set<String> = mutableSetOf("foo")
. A
variável é constante e o tipo declarado não é mutável, mas a
implementação dela ainda é mutável. O compilador do Compose não tem certeza da
imutabilidade dessa classe, já que só vê o tipo declarado. Portanto, ela marca
tags
como instável.