Diagnostica i problemi di stabilità

Se riscontri problemi di prestazioni dovuti a una ricomposizione non necessaria o eccessiva, devi eseguire il debug della stabilità della tua app. Questa guida illustra diversi metodi per farlo.

Layout Inspector

Layout Inspector in Android Studio ti consente di vedere quali componibili vengono ricomposti nella tua app. Mostra il numero di volte in cui Compose ha ricomposto o saltato un componente.

Conteggi di ricomposizione e salti in Layout Inspector

Report del compilatore Compose

Il compilatore Compose può generare i risultati della sua inferenza di stabilità per l'ispezione. Utilizzando questo output, puoi determinare quali dei tuoi componibili sono ignorabili e quali no. Le sezioni seguenti riassumono come utilizzare questi report, ma per informazioni più dettagliate consulta la documentazione tecnica.

Configurazione

I report del compilatore Compose non sono abilitati per impostazione predefinita. Puoi attivarli con un flag del compilatore. La configurazione esatta varia a seconda del progetto, ma per i progetti che utilizzano il plug-in Gradle del compilatore Compose puoi aggiungere quanto segue nel file build.gradle di ogni modulo.

  android { ... }

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

I report del compilatore Compose verranno ora generati durante la creazione del progetto.

Output di esempio

reportsDestination genera tre file. Di seguito sono riportati alcuni esempi di output di JetSnack.

  • <modulename>-classes.txt: un report sulla stabilità delle classi in questo modulo. Esempio.
  • <modulename>-composables.txt: un report su quanto i composable sono riavviabili e ignorabili nel modulo. Esempio.
  • <modulename>-composables.csv:una versione CSV del report sui componibili che puoi importare in un foglio di lavoro o elaborare utilizzando uno script. Esempio

Report sugli elementi componibili

Il file composables.txt descrive in dettaglio ogni funzione componibile per il modulo specificato, inclusa la stabilità dei relativi parametri e se sono riavviabili o ignorabili. Di seguito è riportato un esempio ipotetico di 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
)

In questo esempio, ogni parametro di SnackCollection è contrassegnato come stable, quindi Compose confronta ogni parametro utilizzando l'uguaglianza strutturale (Object.equals()). Sebbene i parametri stable siano ideali per i valori primitivi e le classi di dati piccole e piatte con controlli .equals() economici, forzare i modelli che contengono raccolte (come un SnackCollection che aggrega un List<Snack>) a essere stable fa sì che Compose chiami .equals() su ogni elemento in ogni ricomposizione. Con la modalità di skipping avanzata attiva, è preferibile mantenere i modelli che contengono raccolte unstable, in modo che Compose li confronti utilizzando l'uguaglianza delle istanze (===).

In alternativa, considera un altro esempio generato con la modalità di skipping avanzato disattivata:

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
)

Quando la modalità di strong skipping è disattivata (prima di Kotlin 2.0.20), il componibile HighlightedSnacks non è ignorabile: Compose non lo ignora mai durante la ricomposizione, anche se nessuno dei suoi parametri è cambiato, a causa del parametro unstable snacks.

Con la modalità di salto avanzata attivata (impostazione predefinita in Kotlin 2.0.20 e versioni successive), HighlightedSnacks è contrassegnato come skippable e Compose confronta il parametro unstable snacks utilizzando l'uguaglianza delle istanze (===). Di conseguenza, Compose salta HighlightedSnacks se viene passato lo stesso riferimento List e lo ricompone solo se viene passata un'istanza List appena allocata.

Report Corsi

Il file classes.txt contiene un report simile sulle classi nel modulo specificato. Il seguente snippet è l'output per la 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
}

Per riferimento, di seguito è riportata la definizione di Snack:

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

Il compilatore Compose ha contrassegnato Snack come instabile. Questo perché il tipo di parametro tags è Set<String>. Questo è un tipo immutabile, dato che non è un MutableSet. Tuttavia, le classi di raccolta standard come Set, List e Map sono in definitiva interfacce. Pertanto, l'implementazione sottostante potrebbe essere ancora modificabile.

Ad esempio, potresti scrivere val set: Set<String> = mutableSetOf("foo"). La variabile è costante e il tipo dichiarato non è modificabile, ma la sua implementazione è ancora modificabile. Il compilatore Compose non può essere sicuro dell'immutabilità di questa classe, poiché vede solo il tipo dichiarato. Pertanto, contrassegna tags come instabile.