Compose betrachtet Typen entweder als stabil oder als instabil. Ein Typ ist stabil, wenn er unveränderlich ist oder wenn Compose erkennen kann, ob sich sein Wert zwischen Neuzusammensetzungen geändert hat. Ein Typ ist instabil, wenn Compose nicht erkennen kann, ob sich sein Wert zwischen Neuzusammensetzungen geändert hat.
Compose verwendet die Stabilität der Parameter einer zusammensetzbaren Funktion, um zu bestimmen, wie Eingaben verglichen werden sollen, und um zu entscheiden, ob die zusammensetzbare Funktion während der Neuzusammensetzung übersprungen werden kann. Ab Kotlin 2.0.20 ist der Modus für starkes Überspringen standardmäßig aktiviert:
- Stabile Parameter: Compose vergleicht stabile Parameter anhand der strukturellen Gleichheit (
Object.equals()). Wenn die stabilen Parameter einer zusammensetzbaren Funktion mit ihren vorherigen Werten übereinstimmen, überspringt Compose sie. - Instabile Parameter:Wenn der Modus „Starkes Überspringen“ aktiviert ist (Standard in Kotlin 2.0.20 und höher), vergleicht Compose instabile Parameter anhand der Instanzgleichheit (
===) und überspringt die zusammensetzbare Funktion, wenn dieselben Objektinstanzen übergeben werden. In Versionen vor Kotlin 2.0.20 (oder wenn der Modus „Starkes Überspringen“ deaktiviert ist) wird eine zusammensetzbare Funktion mit instabilen Parametern immer neu zusammengesetzt, wenn die übergeordnete Funktion neu zusammengesetzt wird.
Wenn Ihre App häufig neue Instanzen instabiler Parameter zuweist oder durch übermäßige Annotation von Modellen aufwendige .equals()-Prüfungen für große Sammlungen erzwingt, kann es zu unnötigen Neuzusammensetzungen oder Vergleichsaufwand kommen.
In diesem Dokument wird beschrieben, wie Compose die Stabilität bestimmt und wie Sie sie optimieren können, um die Leistung und die allgemeine Nutzerfreundlichkeit zu verbessern.
Unveränderliche Objekte
Die folgenden Snippets veranschaulichen die allgemeinen Prinzipien hinter Stabilität und Neuzusammensetzung.
Die Klasse Contact ist eine unveränderliche Datenklasse. Das liegt daran, dass alle Parameter Primitive sind, die mit dem Schlüsselwort val definiert werden. Nachdem Sie eine Instanz von Contact erstellt haben, können Sie den Wert der Attribute des Objekts nicht mehr ändern.
Wenn Sie dies versuchen, erstellen Sie ein neues Objekt.
data class Contact(val name: String, val number: String)
Die komponierbare Funktion ContactRow hat einen Parameter vom Typ Contact.
@Composable
fun ContactRow(contact: Contact, modifier: Modifier = Modifier) {
var selected by remember { mutableStateOf(false) }
Row(modifier) {
ContactDetails(contact)
ToggleButton(selected, onToggled = { selected = !selected })
}
}
Überlegen Sie, was passiert, wenn der Nutzer auf den Schalter klickt und sich der Status selected ändert:
- Compose prüft, ob der Code in
ContactRowneu zusammengesetzt werden muss. - Es erkennt, dass das einzige Argument für
ContactDetailsvom TypContactist. - Da
Contacteine unveränderliche Datenklasse ist, ist sich Compose sicher, dass sich keines der Argumente fürContactDetailsgeändert hat. - Daher überspringt Compose
ContactDetailsund führt keine Neuzusammensetzung durch. - Die Argumente für
ToggleButtonhaben sich jedoch geändert und Compose setzt diese Komponente neu zusammen.
Veränderliche Objekte
Im vorherigen Beispiel wird ein unveränderliches Objekt verwendet. Es ist jedoch möglich, ein veränderliches Objekt zu erstellen. Sehen Sie sich das folgende Snippet an:
data class Contact(var name: String, var number: String)
Da jeder Parameter von Contact jetzt ein var ist, ist die Klasse nicht mehr unveränderlich.
Wenn sich die Eigenschaften ändern, würde Compose das nicht bemerken. Das liegt daran, dass Compose nur Änderungen an State-Objekten von Compose verfolgt.
Compose betrachtet eine solche Klasse als instabil. Im Modus „Starkes Überspringen“ (Kotlin 2.0.20+) vergleicht Compose Contact anhand der Instanzgleichheit (===): Wenn contact.name direkt geändert wird, wird keine Neuzusammensetzung ausgelöst. Wenn jedoch eine neu zugewiesene Contact-Instanz mit identischen Werten übergeben wird, wird ContactDetails trotzdem neu zusammengesetzt. Ohne den Modus „Starkes Überspringen“ wird ContactDetails jedes Mal neu zusammengesetzt, wenn sich selected ändert.
Implementierung in Compose
Es kann hilfreich, aber nicht entscheidend sein, zu überlegen, wie genau Compose bestimmt, welche Funktionen bei der Neuzusammensetzung übersprungen werden sollen.
Wenn der Compose-Compiler Ihren Code ausführt, wird jede Funktion und jeder Typ mit einem von mehreren Tags gekennzeichnet. Diese Tags geben an, wie Compose die Funktion oder den Typ während der Neuzusammensetzung verarbeitet.
Funktionen
Compose kann Funktionen als skippable oder restartable markieren. Eine Funktion kann als eine, beide oder keine der folgenden Optionen gekennzeichnet werden:
- Überspringbar: Wenn der Compiler eine zusammensetzbare Funktion als überspringbar markiert, kann Compose sie während der Neuzusammensetzung überspringen, wenn alle ihre Argumente mit ihren vorherigen Werten übereinstimmen. (Mit dem Modus für starkes Überspringen in Kotlin 2.0.20+ können alle neustartbaren Composables automatisch übersprungen werden.)
- Neustartbar: Eine neustartbare zusammensetzbare Funktion dient als „Bereich“, in dem die Neuzusammensetzung beginnen kann. Mit anderen Worten: Die Funktion kann ein Einstiegspunkt sein, an dem Compose nach Statusänderungen mit der erneuten Ausführung von Code für die Neuzusammensetzung beginnen kann.
Typen
Compose kennzeichnet Typen entweder als unveränderlich oder als stabil. Jeder Typ ist entweder das eine oder das andere:
- Unveränderlich: Compose kennzeichnet einen Typ als unveränderlich, wenn sich der Wert seiner Properties nie ändern kann und alle Methoden referenziell transparent sind.
- Beachten Sie, dass alle primitiven Typen als unveränderlich gekennzeichnet sind. Dazu gehören
String,IntundFloat.
- Beachten Sie, dass alle primitiven Typen als unveränderlich gekennzeichnet sind. Dazu gehören
- Stabil: Gibt einen Typ an, dessen Eigenschaften sich nach der Erstellung ändern können. Wenn sich diese Properties während der Laufzeit ändern, wird Compose über diese Änderungen informiert.
Stabilität des Debuggings
Wenn Ihre App eine zusammensetzbare Funktion neu zusammensetzt, deren Parameter sich nicht geändert haben, prüfen Sie zuerst, ob bei jeder Neuzusammensetzung neue Instanzen instabiler Typen zugewiesen werden. Wenn der Modus „Starkes Überspringen“ deaktiviert ist, prüfen Sie, ob die zusammensetzbare Funktion Parameter mit var- oder val-Eigenschaften eines instabilen Typs hat.
Ausführliche Informationen zur Diagnose komplexer Probleme mit der Stabilität in Compose finden Sie im Leitfaden Stabilität debuggen.
Stabilitätsprobleme beheben
Informationen dazu, wie Sie Ihre Compose-Implementierung stabilisieren können, finden Sie im Leitfaden Stabilitätsprobleme beheben.
Zusammenfassung
Beachten Sie Folgendes:
- Parameter: Compose bestimmt die Stabilität jedes Parameters Ihrer Composables, um zu entscheiden, ob sie während der Neuzusammensetzung anhand der strukturellen Gleichheit (
.equals()) oder der Instanzgleichheit (===) verglichen werden sollen. - Sofortige Fehlerbehebung: Wenn Sie feststellen, dass Ihre zusammensetzbare Funktion nicht übersprungen wird und dies ein Leistungsproblem verursacht, prüfen Sie, ob bei jedem Durchlauf neue Instanzen instabiler Parameter erstellt werden oder ob
var-Properties anstelle vonStateverwendet werden. - Compiler-Berichte: Mit den Compiler-Berichten können Sie feststellen, welche Stabilität für Ihre Klassen abgeleitet wird.
- Sammlungen: Compose betrachtet Standard-Sammlungsschnittstellen (
List,SetundMap) als instabil, da ihre zugrunde liegenden Implementierungen veränderlich sein können. Im Modus für starkes Überspringen (standardmäßig in Kotlin 2.0.20+ aktiviert) wird die Neuzusammensetzung bei instabilen Sammlungen weiterhin übersprungen, wenn sich die Sammlungsreferenz nicht ändert. Dazu wird die Instanzgleichheit (===) verwendet. Seien Sie vorsichtig, wenn Sie Standardsammlungen durch unveränderliche Kotlinx-Sammlungen ersetzen oder Klassen, die Sammlungen enthalten, mit@Immutableoder@Stableannotieren, da der Vergleich jedes Elements mit.equals()bei jedem Rekompositionsdurchlauf teurer sein kann als die Rekomposition selbst. - Andere Module: Compose betrachtet Klassen aus Modulen, in denen der Compose-Compiler nicht ausgeführt wird, als instabil (im Vergleich mit
===im Modus „Starkes Überspringen“). Wenn eine Datenquelle häufig kleine, flache Modelle aus Nicht-Compose-Modulen mit identischen Werten neu instanziiert, können Sie eine Konfigurationsdatei für die Stabilität konfigurieren oder@Stableoder@Immutableverwenden, wobei.equals()kostengünstig ist.
Weitere Informationen
- Leistung: Weitere Tipps zur Fehlerbehebung bei der Compose-Leistung finden Sie in unserem Leitfaden mit Best Practices und im I/O-Vortrag.