Stabilità nella scrittura

Compose considera i tipi stabili o instabili. Un tipo è stabile se è immutabile o se Compose è in grado di sapere se il suo valore è cambiato tra una ricomposizione e l'altra. Un tipo è instabile se Compose non può sapere se il suo valore è cambiato tra una ricomposizione e l'altra.

Compose utilizza la stabilità dei parametri di un componibile per determinare se può saltare il componibile durante la ricomposizione:

  • Parametri stabili: se un componibile ha parametri stabili che non sono cambiati, Compose ignora l'elemento.
  • Parametri instabili: se un componibile ha parametri instabili, Compose lo ricompone sempre quando ricompone il principale del componente.

Se la tua app include molti componenti inutilmente instabili che Compose sempre ricompone, potresti riscontrare problemi di prestazioni e altri problemi.

Questo documento descrive come aumentare la stabilità della tua app per migliorare le prestazioni e l'esperienza utente in generale.

Oggetti immutabili

I seguenti snippet dimostrano i principi generali alla base della stabilità e della ricomposizione.

La classe Contact è una classe di dati immutabile. Questo perché tutti i parametri sono primitivi definiti con la parola chiave val. Una volta creata un'istanza di Contact, non puoi modificare il valore delle proprietà dell'oggetto. Se tenti di farlo, devi creare un nuovo oggetto.

data class Contact(val name: String, val number: String)

L'elemento componibile ContactRow ha un parametro di tipo Contact.

@Composable
fun ContactRow(contact: Contact, modifier: Modifier = Modifier) {
   var selected by remember { mutableStateOf(false) }

   Row(modifier) {
      ContactDetails(contact)
      ToggleButton(selected, onToggled = { selected = !selected })
   }
}

Considera cosa succede quando l'utente fa clic sul pulsante di attivazione/disattivazione e lo stato selected cambia:

  1. Compose valuta se deve ricomporre il codice all'interno di ContactRow.
  2. Vede che l'unico argomento per ContactDetails è di tipo Contact.
  3. Poiché Contact è una classe di dati immutabile, Compose garantisce che nessuno degli argomenti per ContactDetails sia cambiato.
  4. Di conseguenza, Compose ignora ContactDetails e non lo ricompone.
  5. Gli argomenti di ToggleButton sono invece cambiati e Compose ricompone il componente.

Oggetti modificabili

Sebbene l'esempio precedente utilizzi un oggetto immutabile, è possibile creare un oggetto modificabile. Considera il seguente snippet:

data class Contact(var name: String, var number: String)

Poiché ogni parametro di Contact ora è un var, la classe non è più immutabile. Se le sue proprietà cambiassero, Compose non veniva a conoscenza. Il motivo è che Compose tiene traccia solo delle modifiche apportate agli oggetti State Compose.

Compose considera questo corso instabile. Compose non ignora la ricomposizione di classi instabili. Di conseguenza, se Contact fosse definito in questo modo, ContactRow nell'esempio precedente si ricomponeva ogni volta che selected viene modificato.

Implementazione in Compose

Può essere utile, ma non cruciale, considerare in che modo Compose determina esattamente quali funzioni ignorare durante la ricomposizione.

Quando il compilatore Compose viene eseguito sul tuo codice, contrassegna ogni funzione e tipo con uno dei vari tag. Questi tag riflettono il modo in cui Compose gestisce la funzione o il tipo durante la ricomposizione.

Funzioni

La funzionalità di scrittura può contrassegnare le funzioni come skippable o restartable. Tieni presente che potrebbe contrassegnare una funzione come una, entrambe o nessuna di queste:

  • Ignorabile: se il compilatore contrassegna un componibile come ignorabile, Compose può saltarlo durante la ricomposizione se tutti i suoi argomenti sono uguali ai valori precedenti.
  • Riavviabile: un componibile riavviabile funge da "ambito" in cui può iniziare la ricomposizione. In altre parole, la funzione può essere un punto di ingresso in cui Compose può iniziare a rieseguire il codice per la ricomposizione dopo le modifiche di stato.

Tipi

Compose contrassegna i tipi come immutabili o stabili. Ogni tipo è uno o l'altro:

  • Immutabile: la scrittura contrassegna un tipo come immutabile se il valore delle sue proprietà non può mai cambiare e tutti i metodi sono referenzialmente trasparenti.
    • Tieni presente che tutti i tipi primitivi sono contrassegnati come immutabili. Questi includono String, Int e Float.
  • Stabile: indica un tipo le cui proprietà possono essere modificate dopo la costruzione. Se e quando queste proprietà cambiano durante il runtime, Compose verrà a conoscenza di queste modifiche.

Debug della stabilità

Se la tua app ricompone un componibile i cui parametri non sono stati modificati, verifica innanzitutto la definizione di parametri chiaramente modificabili. Compose ricompone sempre un componente se passi un tipo con proprietà var o una proprietà val che utilizza un tipo instabile noto.

Per informazioni dettagliate su come diagnosticare problemi complessi relativi alla stabilità in Compose, consulta la guida Debug della stabilità.

Risolvi i problemi di stabilità

Per informazioni su come garantire stabilità all'implementazione di Compose, consulta la guida Risolvere i problemi di stabilità.

Riepilogo

In generale, tieni presente quanto segue:

  • Parametri: Compose determina la stabilità di ciascun parametro dei componibili per determinare quali componibili ignorare durante la ricomposizione.
  • Correzioni immediate: se noti che il tuo componibile non viene ignorato e causa un problema di prestazioni, devi prima verificare le cause ovvie dell'instabilità, come i parametri var.
  • Report del compilatore: è possibile utilizzare i report del compilatore per determinare quale stabilità viene dedotta dalle classi.
  • Raccolte: Compose considera sempre instabili le classi di raccolta, ad esempio List, Set e Map. perché non è possibile garantire che siano immutabili. Puoi utilizzare invece raccolte immutabili Kotlinx o annotare i tuoi corsi come @Immutable o @Stable.
  • Altri moduli: Compose considera sempre instabile quando provengono da moduli in cui il compilatore Compose non viene eseguito. Se necessario, inserisci le classi in classi di modello UI.

Continua a leggere