Di fronte a una classe instabile che causa prestazioni problemi, devi renderla stabile. Questo documento illustra diverse tecniche che può utilizzare per farlo.
Attiva l'opzione Ignora forte
Dovresti prima provare ad attivare la modalità di salto forte. Modalità di salto potente consente di saltare gli elementi componibili con parametri instabili ed è il metodo per risolvere i problemi di prestazioni causati dalla stabilità.
Per ulteriori informazioni, consulta la sezione Saltare in modo forzato.
Rendi il corso immutabile
Puoi anche provare a rendere una classe instabile del tutto immutabile.
- Immutabile: indica un tipo in cui il valore di qualsiasi proprietà non può mai
modificare dopo la creazione di un'istanza di quel tipo e tutti i metodi vengono
referenzialmente trasparenti.
- Assicurati che tutte le proprietà della classe siano entrambe
val
anzichévar
, e di tipi immutabili. - I tipi primitivi come
String, Int
eFloat
sono sempre immutabili. - Se non è possibile, devi utilizzare lo stato di composizione per proprietà modificabili.
- Assicurati che tutte le proprietà della classe siano entrambe
- Stabile: indica un tipo modificabile. Il runtime di Compose venire a conoscenza se e quando qualsiasi proprietà o metodo pubblico del tipo questo comportamento produrrà risultati diversi rispetto a una chiamata precedente.
Raccolte immutabili
Un motivo comune per cui Compose considera una classe instabile sono le raccolte. Come indicato
Nella pagina Diagnosticare i problemi di stabilità, il compilatore Compose
non possono essere completamente sicure che raccolte quali List, Map
e Set
siano
immutabili e di conseguenza li contrassegna come instabili.
Per risolvere questo problema, puoi utilizzare le raccolte immutabili. Compilatore Compose include il supporto per le Raccolte immutabili di Kotlinx. Questi Le raccolte sono garantite per essere immutabili e il compilatore Compose le tratta come tale. Questa libreria è ancora in versione alpha, quindi sono previste possibili modifiche alla relativa API.
Considera di nuovo questa classe instabile dalla sezione Diagnostica di stabilità ai problemi:
unstable class Snack {
…
unstable val tags: Set<String>
…
}
Puoi rendere stabile tags
utilizzando una raccolta immutabile. In classe, cambia
tipo di tags
a ImmutableSet<String>
:
data class Snack{
…
val tags: ImmutableSet<String> = persistentSetOf()
…
}
Dopodiché, tutti i parametri della classe sono immutabili e il comando Compose il compilatore contrassegna la classe come stabile.
Aggiungi annotazioni con Stable
o Immutable
Un possibile percorso per risolvere i problemi di stabilità è annotare le classi instabili
con @Stable
o @Immutable
.
L'annotazione di una classe ha la precedenza su ciò che altrimenti verrebbe fatto dal compilatore
inferire sul tuo corso. È simile
!!
operatore in Kotlin. Dovresti essere molto
fai attenzione a come usi queste annotazioni. Override del comportamento del compilatore
potresti incorrere in bug imprevisti, come la mancata ricomposizione del componibile
come ti aspetti.
Se è possibile rendere stabile la classe senza un'annotazione, dovresti cercare di raggiungere la stabilità in questo modo.
Lo snippet seguente fornisce un esempio minimo di una classe di dati annotata come immutabile:
@Immutable
data class Snack(
…
)
Sia che utilizzi l'annotazione @Immutable
o @Stable
, il compilatore Compose
contrassegna la classe Snack
come stabile.
Classi annotate nelle raccolte
Considera un componibile che include un parametro di tipo List<Snack>
:
restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
…
unstable snacks: List<Snack>
…
)
Anche se annota Snack
con @Immutable
, il compilatore Compose contrassegna comunque
il parametro snacks
in HighlightedSnacks
come instabile.
I parametri devono affrontare lo stesso problema delle classi per quanto riguarda i tipi di raccolta.
il compilatore Compose contrassegna sempre un parametro di tipo List
come instabile, anche
quando si tratta di una raccolta di tipi stabili.
Non puoi contrassegnare un singolo parametro come stabile, né puoi annotare un componibili in modo che siano sempre ignorabili. Sono presenti più percorsi per il progresso.
Esistono diversi modi per risolvere il problema delle raccolte instabili. Le seguenti sottosezioni descrivono questi diversi approcci.
File di configurazione
Se vuoi rispettare il contratto di stabilità nel tuo codebase,
puoi scegliere di considerare stabili le raccolte Kotlin aggiungendo
kotlin.collections.*
al tuo
file di configurazione della stabilità.
Raccolta immutabile
Per la sicurezza dell'immutabilità in fase di compilazione, puoi
utilizza una raccolta immutabile di kotlinx anziché List
.
@Composable
private fun HighlightedSnacks(
…
snacks: ImmutableList<Snack>,
…
)
Wrapper
Se non puoi utilizzare una raccolta immutabile, puoi crearne una personalizzata. Per farlo,
aggrega List
in una classe stabile annotata. Un wrapper generico è probabilmente
la scelta migliore, a seconda delle tue esigenze.
@Immutable
data class SnackCollection(
val snacks: List<Snack>
)
Questo valore può essere utilizzato come tipo di parametro nel componibile.
@Composable
private fun HighlightedSnacks(
index: Int,
snacks: SnackCollection,
onSnackClick: (Long) -> Unit,
modifier: Modifier = Modifier
)
Soluzione
Dopo aver seguito uno di questi approcci, il compilatore Compose ora contrassegna
HighlightedSnacks
Componibile sia come skippable
che come restartable
.
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
stable index: Int
stable snacks: ImmutableList<Snack>
stable onSnackClick: Function1<Long, Unit>
stable modifier: Modifier? = @static Companion
)
Durante la ricomposizione, ora Compose può saltare HighlightedSnacks
se nessuno dei suoi
sono cambiati.
File di configurazione della stabilità
A partire da Compose Compiler 1.5.5, un file di configurazione di classi
che può essere fornito in fase di compilazione. Ciò consente di considerare
che non controlli, come le classi della libreria standard
come LocalDateTime
, come stabile.
Il file di configurazione è un file di testo normale con una classe per riga. Commenti sono supportati i caratteri jolly singoli e doppi. Di seguito è riportato un esempio di configurazione:
// Consider LocalDateTime stable
java.time.LocalDateTime
// Consider kotlin collections stable
kotlin.collections.*
// Consider my datalayer and all submodules stable
com.datalayer.**
// Consider my generic type stable based off it's first type parameter only
com.example.GenericClass<*,_>
Per attivare questa funzionalità, passa il percorso del file di configurazione a Compose del compilatore.
Alla moda
kotlinOptions {
freeCompilerArgs += [
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=" +
project.absolutePath + "/compose_compiler_config.conf"
]
}
Kotlin
kotlinOptions {
freeCompilerArgs += listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=" +
"${project.absolutePath}/compose_compiler_config.conf"
)
}
Poiché il compilatore Compose viene eseguito separatamente su ciascun modulo del tuo progetto, puoi fornire configurazioni diverse ai vari moduli, se necessario. In alternativa, crea un a livello principale del progetto e trasmetti il percorso a ogni in maggior dettaglio più avanti in questo modulo.
Più moduli
Un altro problema comune riguarda l'architettura multimodulo. Compilatore Compose può dedurre se una classe è stabile solo se tutti i tipi non primitivi che i riferimenti sono contrassegnati esplicitamente come stabili o in un modulo anche creato con il compilatore Compose.
Se il livello dati si trova in un modulo separato da quello dell'interfaccia utente, ovvero potrebbe essere un problema che potresti riscontrare.
Soluzione
Per risolvere il problema, puoi adottare uno dei seguenti approcci:
- Aggiungi i corsi al file di configurazione del compilatore.
- Attiva il compilatore Compose nei moduli del livello dati o tagga i tuoi corsi
con
@Stable
o@Immutable
, ove opportuno.- Ciò comporta l'aggiunta di una dipendenza Compose al livello dati. Tuttavia,
si tratta solo della dipendenza per il runtime di Compose e non per
Compose-UI
.
- Ciò comporta l'aggiunta di una dipendenza Compose al livello dati. Tuttavia,
si tratta solo della dipendenza per il runtime di Compose e non per
- All'interno del modulo UI, aggrega le classi del livello dati in un wrapper specifico per l'interfaccia utente. .
Lo stesso problema si verifica anche quando si utilizzano librerie esterne se non utilizzano Crea il compilatore.
Non tutti i componibili devono essere ignorabili
Quando lavori per risolvere problemi di stabilità, non cercare di risolvere ogni ignorabile componibile. Cercare di farlo può portare a un'ottimizzazione prematura che introduce più problemi che come risolvere.
Ci sono molte situazioni in cui essere ignorabili non offre alcun vantaggio reale e può causare complicazioni di manutenzione. Ad esempio:
- Un componibile che non viene ricomposto spesso o affatto.
- Un componibile che di per sé chiama semplicemente elementi componibili ignorabili.
- Un componibile con un gran numero di parametri con conversioni costose implementazioni. In questo caso, il costo del controllo di eventuali parametri può superare il costo di una ricomposizione economica.
Quando un componibile è ignorabile, aggiunge un piccolo overhead che potrebbe non valere li annotino. Puoi persino annotare il tuo componibile in modo che sia non riavviabile nei casi in cui determini che il riavvio è più overhead di quanto valga.