Auf dieser Seite erfahren Sie mehr über den Lebenszyklus einer zusammensetzbaren Funktion und wie Compose entscheidet, ob eine zusammensetzbare Funktion neu zusammengesetzt werden muss.
Lebenszyklusübersicht
Wie in der Dokumentation zur Statusverwaltung erwähnt, beschreibt eine Komposition die Benutzeroberfläche Ihrer App und wird durch das Ausführen von zusammensetzbaren Funktionen erstellt. Eine Komposition ist eine Baumstruktur der zusammensetzbaren Funktionen, die Ihre Benutzeroberfläche beschreiben.
Wenn Jetpack Compose Ihre zusammensetzbaren Funktionen zum ersten Mal ausführt, erfasst es bei der ersten Komposition die zusammensetzbaren Funktionen, die Sie aufrufen, um Ihre UI in einer Komposition zu beschreiben. Wenn sich dann der Status der Anwendung ändert, plant Jetpack Composer eine Neuzusammensetzung. Bei der Neuzusammensetzung führt Jetpack Compose die zusammensetzbaren Funktionen, die sich als Reaktion auf Statusänderungen geändert haben, neu aus und aktualisiert dann die Zusammensetzung, um alle Änderungen widerzuspiegeln.
Eine Komposition kann nur durch eine anfängliche Komposition erstellt und durch Neuzusammensetzung aktualisiert werden. Eine Komposition kann nur durch Neuzusammensetzung geändert werden.
Abbildung 1: Lebenszyklus einer zusammensetzbaren Funktion in der Zusammensetzung Er tritt in die Komposition ein, wird null oder öfter neu zusammengesetzt und verlässt die Komposition.
Die Neuzusammensetzung wird normalerweise durch eine Änderung an einem State<T>
-Objekt ausgelöst. „Compose“ verfolgt diese und führt alle zusammensetzbaren Funktionen in der Komposition aus, die diese bestimmte State<T>
lesen, sowie alle von ihnen aufgerufenen zusammensetzbaren Funktionen, die nicht übersprungen werden können.
Wenn eine zusammensetzbare Funktion mehrmals aufgerufen wird, werden mehrere Instanzen in der Komposition platziert. Jeder Aufruf hat in der Zusammensetzung seinen eigenen Lebenszyklus.
@Composable fun MyComposable() { Column { Text("Hello") Text("World") } }
Abbildung 2: Darstellung von MyComposable
in der Komposition. Wenn eine zusammensetzbare Funktion mehrmals aufgerufen wird, werden mehrere Instanzen in der Komposition platziert. Ein Element mit einer anderen Farbe weist darauf hin, dass es eine separate Instanz ist.
Anatomie einer Zusammensetzung in einer Komposition
Die Instanz einer zusammensetzbaren Funktion in der Komposition wird durch die entsprechende Aufrufwebsite identifiziert. Der Compose-Compiler betrachtet jede Aufruf-Website als eigenständige Website. Durch das Aufrufen von Zusammensetzbaren von mehreren Aufrufwebsites werden mehrere Instanzen der zusammensetzbaren Funktion in der Komposition erstellt.
Wenn eine zusammensetzbare Funktion während einer Neuzusammensetzung andere zusammensetzbare Funktionen aufruft als während der vorherigen Zusammensetzung, erkennt Compose, welche Zusammensetzungen aufgerufen wurden oder nicht. Für die zusammensetzbaren Funktionen, die in beiden Kompositionen aufgerufen wurden, vermeidet Compose eine Neuzusammensetzung, wenn sich die Eingaben nicht geändert haben.
Die Bewahrung der Identität ist entscheidend, um Nebenwirkungen mit der zusammensetzbaren Funktion zu verknüpfen, damit sie erfolgreich abgeschlossen werden kann und nicht bei jeder Neuzusammensetzung neu gestartet werden kann.
Betrachten Sie das folgende Beispiel:
@Composable fun LoginScreen(showError: Boolean) { if (showError) { LoginError() } LoginInput() // This call site affects where LoginInput is placed in Composition } @Composable fun LoginInput() { /* ... */ } @Composable fun LoginError() { /* ... */ }
Im Code-Snippet oben ruft LoginScreen
die zusammensetzbare Funktion LoginError
und immer die zusammensetzbare Funktion LoginInput
auf. Jeder Aufruf hat eine eindeutige Aufrufwebsite und Quellposition, anhand derer der Compiler ihn eindeutig identifiziert.
Abbildung 3: Darstellung von LoginScreen
in der Komposition, wenn sich der Status ändert und eine Neuzusammensetzung stattfindet. Die gleiche Farbe bedeutet, dass es nicht neu zusammengesetzt wurde.
Obwohl LoginInput
statt zuerst zuerst aufgerufen wurde, wird die Instanz LoginInput
bei Neuzusammensetzungen beibehalten. Da LoginInput
keine Parameter hat, die sich bei der Neuzusammensetzung geändert haben, wird der Aufruf von LoginInput
von „Compose“ übersprungen.
Zusätzliche Informationen für eine intelligente Neuzusammensetzung hinzufügen
Wenn eine zusammensetzbare Funktion mehrmals aufgerufen wird, wird sie auch mehrmals zur Komposition hinzugefügt. Wenn eine zusammensetzbare Funktion mehrmals von derselben Aufrufwebsite aufgerufen wird, verfügt Compose nicht über Informationen, um jeden Aufruf dieser zusammensetzbaren Funktion eindeutig zu identifizieren. Daher wird zusätzlich zur Aufrufwebsite die Ausführungsreihenfolge verwendet, um die Instanzen voneinander zu unterscheiden. Manchmal reicht dieses Verhalten aus, es kann aber in einigen Fällen zu unerwünschtem Verhalten führen.
@Composable fun MoviesScreen(movies: List<Movie>) { Column { for (movie in movies) { // MovieOverview composables are placed in Composition given its // index position in the for loop MovieOverview(movie) } } }
Im obigen Beispiel verwendet Compose zusätzlich zur Aufrufwebsite die Ausführungsreihenfolge, damit die Instanz in der Komposition klar erkennbar bleibt. Wenn am unten der Liste eine neue movie
hinzugefügt wird, kann Compose die Instanzen wiederverwenden, die sich bereits in der Komposition befinden, da sich ihre Position in der Liste nicht geändert hat. Daher ist die movie
-Eingabe für diese Instanzen dieselbe.
Abbildung 4: Darstellung von MoviesScreen
in der Komposition, wenn am Ende der Liste ein neues Element hinzugefügt wird. Die zusammensetzbaren Funktionen MovieOverview
in der Komposition können wiederverwendet werden. Dieselbe Farbe in MovieOverview
bedeutet, dass die zusammensetzbare Funktion nicht neu zusammengesetzt wurde.
Wenn sich die movies
-Liste jedoch ändert, indem Elemente entweder zum oben oder in der Mitte der Liste hinzugefügt oder Elemente entfernt oder neu angeordnet werden, führt dies zu einer Neuzusammensetzung in allen MovieOverview
-Aufrufen, deren Eingabeparameter die Position in der Liste geändert hat. Das ist beispielsweise äußerst wichtig, wenn MovieOverview
ein Filmbild mithilfe eines Nebeneffekts abruft. Findet eine Neuzusammensetzung während des Effekts statt, wird er abgebrochen und beginnt von vorn.
@Composable fun MovieOverview(movie: Movie) { Column { // Side effect explained later in the docs. If MovieOverview // recomposes, while fetching the image is in progress, // it is cancelled and restarted. val image = loadNetworkImage(movie.url) MovieHeader(image) /* ... */ } }
Abbildung 5: Darstellung von MoviesScreen
in der Komposition, wenn der Liste ein neues Element hinzugefügt wird Zusammensetzbare MovieOverview
-Elemente können nicht wiederverwendet werden und alle Nebeneffekte werden neu gestartet. Eine andere Farbe in MovieOverview
bedeutet, dass die zusammensetzbare Funktion neu zusammengesetzt wurde.
Im Idealfall ist die Identität der MovieOverview
-Instanz mit der Identität der movie
verknüpft, die an sie übergeben wird. Wenn wir die Liste der Filme neu anordnen, würden wir idealerweise auch die Instanzen im Kompositionsbaum neu anordnen, anstatt jede zusammensetzbare MovieOverview
mit einer anderen Filminstanz neu zusammenzusetzen. Mit der Funktion „Compose“ können Sie der Laufzeit mitteilen, welche Werte zum Identifizieren eines bestimmten Teils der Baumstruktur verwendet werden sollen: der zusammensetzbaren Funktion key
.
Durch das Einbinden eines Codeblocks in einen Aufruf an die zusammensetzbare Schlüsselfunktion mit einem oder mehreren übergebenen Werten werden diese Werte kombiniert, um diese Instanz in der Zusammensetzung zu identifizieren. Der Wert für eine key
muss nicht global eindeutig sein. Er darf nur unter den Aufrufen von zusammensetzbaren Funktionen auf der Aufrufwebsite eindeutig sein. In diesem Beispiel benötigt jedes movie
also ein key
, das unter den movies
eindeutig ist. Es ist in Ordnung, wenn es dieses key
mit einer anderen zusammensetzbaren Funktion an anderer Stelle in der App teilt.
@Composable fun MoviesScreenWithKey(movies: List<Movie>) { Column { for (movie in movies) { key(movie.id) { // Unique ID for this movie MovieOverview(movie) } } } }
Selbst wenn sich die Elemente auf der Liste ändern, erkennt Compose einzelne Aufrufe von MovieOverview
und kann wiederverwendet werden.
Abbildung 6: Darstellung von MoviesScreen
in der Komposition, wenn der Liste ein neues Element hinzugefügt wird Da die zusammensetzbaren Funktionen von MovieOverview
eindeutige Schlüssel haben, erkennt Compose, welche MovieOverview
-Instanzen nicht geändert wurden, und kann diese wiederverwenden. Die Nebeneffekte werden weiterhin ausgeführt.
Einige zusammensetzbare Funktionen unterstützen die zusammensetzbare Funktion key
. Beispielsweise lässt sich für LazyColumn
eine benutzerdefinierte key
in items
DSL angeben.
@Composable fun MoviesScreenLazy(movies: List<Movie>) { LazyColumn { items(movies, key = { movie -> movie.id }) { movie -> MovieOverview(movie) } } }
Überspringen, wenn sich die Eingaben nicht geändert haben
Bei der Neuzusammensetzung kann die Ausführung einiger zusammensetzbarer Funktionen komplett übersprungen werden, wenn sich ihre Eingaben gegenüber der vorherigen Zusammensetzung nicht geändert haben.
Eine zusammensetzbare Funktion kann übersprungen werden, außer
- Die Funktion hat einen Rückgabetyp, der nicht
Unit
ist - Die Funktion ist mit
@NonRestartableComposable
oder@NonSkippableComposable
annotiert. - Ein erforderlicher Parameter ist ein instabiler Typ.
Es gibt den experimentellen Compiler-Modus Strong Skipping, der die letzte Anforderung lockert.
Damit ein Typ als stabil gilt, muss er folgenden Vertrag einhalten:
- Das Ergebnis von
equals
für zwei Instanzen ist immer dasselbe für die beiden Instanzen. - Wenn sich ein öffentliches Eigentum dieses Typs ändert, wird die Komposition benachrichtigt.
- Alle Arten öffentlicher Immobilien sind ebenfalls unverändert.
Es gibt einige wichtige gängige Typen, die unter diesen Vertrag fallen und vom Compiler als stabil behandelt werden, obwohl sie nicht explizit mit der Annotation @Stable
als stabil gekennzeichnet sind:
- Alle primitiven Werttypen:
Boolean
,Int
,Long
,Float
,Char
usw. - Strings
- Alle Funktionstypen (Lambdas)
Alle diese Typen können dem Vertrag der stabilen Version folgen, da sie unveränderlich sind. Da sich unveränderliche Typen niemals ändern, müssen sie die Zusammensetzung nie über die Änderung informieren, sodass es viel einfacher ist, diesen Vertrag einzuhalten.
Ein bemerkenswerter Typ, der stabil ist, aber änderbar ist, ist der MutableState
-Typ von Compose. Wenn ein Wert in einem MutableState
enthalten ist, gilt das Statusobjekt insgesamt als stabil, da Compose über alle Änderungen an der .value
-Eigenschaft von State
benachrichtigt wird.
Wenn alle Typen, die als Parameter an eine zusammensetzbare Funktion übergeben werden, stabil sind, werden die Parameterwerte anhand der zusammensetzbaren Position in der UI-Struktur auf Übereinstimmung geprüft. Die Neuzusammensetzung wird übersprungen, wenn alle Werte seit dem vorherigen Aufruf unverändert sind.
Compose betrachtet einen Typ nur dann als stabil, wenn er dies nachweisen kann. Beispielsweise wird eine Schnittstelle im Allgemeinen als nicht stabil behandelt und Typen mit änderbaren öffentlichen Attributen, deren Implementierung unveränderlich sein könnte, sind ebenfalls nicht stabil.
Wenn Compose nicht ableiten kann, dass ein Typ stabil ist, Sie aber erzwingen möchten, dass Composer als stabil behandelt wird, markieren Sie ihn mit der Annotation @Stable
.
// Marking the type as stable to favor skipping and smart recompositions. @Stable interface UiState<T : Result<T>> { val value: T? val exception: Throwable? val hasError: Boolean get() = exception != null }
Da UiState
im obigen Code-Snippet eine Schnittstelle ist, wird dieser Typ in Compose normalerweise als instabil eingestuft. Durch das Hinzufügen der Annotation @Stable
teilen Sie Compose mit, dass dieser Typ stabil ist, sodass Compose intelligente Neuzusammensetzungen bevorzugt. Das bedeutet auch, dass Compose alle Implementierungen als stabil behandelt, wenn die Schnittstelle als Parametertyp verwendet wird.
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- State und Jetpack Compose
- Nebeneffekte in der Funktion „Schreiben“
- UI-Status in „Compose“ speichern