Recomposition ist ein Mechanismus von Jetpack Compose, der Teile der Benutzeroberfläche automatisch neuerstellt, wenn sich Daten ändern, ohne manuelles Aktualisieren von View-Elementen. Wenn eine Zustandsvariable, von der eine Composable-Funktion abhängt, ihren Wert ändert, startet Compose nur diese Funktion neu und lässt den Rest des UI-Baums unberührt. Laut Google Android Developers, 2026 ermöglicht das richtige Verständnis von Recomposition eine Reduzierung unnötiger Neuzeichnungen um 40–60%.
Wichtige Punkte
Recomposition ist die erneute Ausführung von Composable-Funktionen, die bereits an der Composition teilgenommen haben, mit neuen Parameter- oder Zustandswerten. Das Hauptziel der Rekomposition ist es, den UI-Baum mit aktuellen Daten zu synchronisieren, ohne die gesamte Oberfläche von Grund auf neu zu erstellen. Anders als die Composition, die einmalig erfolgt, kann die Recomposition hunderte Male während der Lebensdauer eines Bildschirms ausgelöst werden.
Recomposition arbeitet nach dem Prinzip der Smart Invalidation: Compose verfolgt, welche State-Objekte jede Composable-Funktion liest, und markiert nur diejenigen für den Neustart, deren Abhängigkeiten sich geändert haben. Dies wird durch ein Snapshot-System erreicht, das alle State-Lesevorgänge während der Ausführung aufzeichnet, und einen Composer, der diese Abhängigkeiten bestimmten Funktionen zuordnet.
Wichtig zu verstehen: Recomposition bedeutet nicht sofortige Bildschirmneuzeichnung. Compose arbeitet in drei Phasen: Composition (Erstellung der UI-Beschreibung), Layout (Berechnung von Größen und Positionen) und Drawing (Rendering auf der Leinwand). Wenn sich nach der Rekomposition die Größen und Positionen der Elemente nicht geändert haben, kann die Layout-Phase übersprungen werden. Wenn sich das visuelle Erscheinungsbild nicht geändert hat — wird Drawing übersprungen. Diese Drei-Phasen-Architektur gewährleistet minimale Kosten für jedes UI-Update.
Es gibt drei Hauptauslöser für Rekomposition. Der erste ist eine Änderung eines State-Objekts, das im Körper einer Composable-Funktion gelesen wurde. Wenn mutableStateOf oder derivedStateOf seinen Wert ändert, werden alle Funktionen, die das Lesen dieses State in der vorherigen Composition registriert haben, für den Neustart markiert.
Der zweite Auslöser ist eine Parameteränderung einer Composable-Funktion beim Aufruf aus einer Elternfunktion. Wenn die Elternfunktion einen neuen Wert übergibt (z.B. hat sich der Text oder die Zahl geändert), wird die Kindfunktion neu gestartet, selbst wenn sie intern keinen State liest. Compose vergleicht neue und alte Parameterwerte per equals, und wenn sie gleich sind — kann die Funktion übersprungen werden.
Der dritte Auslöser ist eine CompositionLocal-Änderung über CompositionLocalProvider. Alle Funktionen, die CompositionLocal über .current lesen, werden beim Wechsel des Providers neu gestartet. Dieser Mechanismus wird von MaterialTheme verwendet: ein Themenwechsel (hell/dunkel) verursacht die Rekomposition aller Komponenten, die MaterialTheme.colorScheme lesen.
@Composable
fun RecompositionDemo() {
var counter by remember { mutableStateOf(0) }
var text by remember { mutableStateOf("Hello") }
Column {
Text("Counter: $counter") // recomposition when counter changes
Text("Message: $text") // recomposition when text changes
Button(onClick = { counter++ }) {
Text("+1")
}
Button(onClick = { text = "World" }) {
Text("Change Text")
}
}
}
Das Klicken auf die +1-Taste ändert counter, was nur die Rekomposition der ersten Text-Zeile und der Column selbst verursacht. Die zweite Text-Zeile, die text anzeigt, wird nicht neu gestartet. Diese Isolierung ist das Ergebnis des Snapshot-Systems: jede Composable-Funktion kennt nur die State-Objekte, die sie gelesen hat.
Die Optimierung der Rekomposition beginnt mit der Wahl der richtigen Datenstrukturen. Verwenden Sie unveränderliche Sammlungen (listOf, mapOf) anstelle von veränderlichen (mutableListOf). Compose vergleicht Parameter per equals, und wenn sich eine Sammlung geändert hat, equals aber true zurückgibt — wird die Funktion nicht neu gestartet. Für veränderliche Sammlungen verwenden Sie SnapshotStateList, das eine korrekte Änderungsverfolgung auf Elementebene implementiert.
Die zweite Technik ist das Auslagern stabiler Teile der UI in separate Composable-Funktionen. Wenn ein Teil des Bildschirms nicht von häufig wechselndem Zustand abhängt, lagern Sie ihn in eine separate Funktion mit Parametern aus. Wenn eine Rekomposition auftritt, erhält die stabile Funktion dieselben Parameter, Compose vergleicht sie und überspringt die Ausführung. Dies ist effizienter, als diesen Teil als Teil einer großen Funktion neu zu starten, bei der sich einige Parameter geändert haben.
Die dritte Technik sind Schlüssel in LazyColumn. Geben Sie immer einen Schlüssel für Elemente in LazyColumn, LazyGrid und anderen faulen Containern an. Der Schlüssel ermöglicht es Compose, Elemente bei Listenänderungen zu identifizieren: Hinzufügen, Entfernen oder Neuanordnen. Ohne Schlüssel startet Compose bei jeder Änderung alle Elemente der Liste neu, was bei großen Listen zu einer spürbaren Leistungseinbuße führt.
// Optimized structure: stable parts extracted separately
@Composable
fun OptimizedScreen(items: List<Item>) {
Column {
Header() // does not depend on items — no recomposition
Spacer(modifier = Modifier.height(8.dp))
LazyColumn {
items(items, key = { it.id }) { item ->
ItemRow(item = item) // recomposition only for changed items
}
}
}
}
@Composable
fun Header() {
Text("Item list", style = MaterialTheme.typography.headlineMedium)
}
@Composable
fun ItemRow(item: Item) {
Text(item.title)
}
Skipping ist ein Mechanismus, bei dem Compose die Ausführung einer Composable-Funktion überspringt, wenn sich alle ihre Parameter nicht geändert haben. Damit Skipping korrekt funktioniert, müssen die Parametertypen stabil (stable) sein. Der Kotlin-Compiler markiert als stabil: primitive Typen (Int, Float, Boolean), String, Lambda-Funktionen sowie Klassen, deren Felder alle stabil und val sind.
Stability ist die Annotation @Stable oder @Immutable, die zu benutzerdefinierten Datenklassen hinzugefügt werden kann. Wenn eine Klasse ein veränderliches Feld (var) enthält, betrachtet der Compiler sie als instabil, und Compose kann Funktionen mit solchen Parametern nicht überspringen. Verwenden Sie für Klassen mit var @Stable, wenn Sie garantieren, dass die Änderungsbenachrichtigung über das Snapshot-System gesendet wird.
Sie können die Stabilität mit dem Compiler-Flag -P "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=. /reports" überprüfen. Es erzeugt einen Bericht mit einer Liste aller Composable-Funktionen und ihrer Parameter unter Angabe der Stabilität. Wenn ein Parameter instabil ist — ist Skipping für diese Funktion unmöglich, und sie wird bei jeder Eltern-Rekomposition neu gestartet.
| Typ | Stabilität | Skipping |
|---|---|---|
| Int, Float, Boolean | Stabil | Ja |
| String | Stabil | Ja |
| Lambda | Stabil | Ja |
| data class mit val-Feldern | Stabil | Ja |
| data class mit var-Feldern | Instabil | Nein |
| List<String> | Instabil | Nein |
Hinweis: List<String> gilt als instabil, da es sich um ein Interface und nicht um eine konkrete Implementierung handelt. Verwenden Sie immutableListOf() aus der Kotlin Collections Immutable-Bibliothek oder wickeln Sie die Liste in eine @Stable-Klasse. Lambda ist immer stabil, da sein equals nur Referenzen vergleicht, und wenn eine neue Lambda an der Aufrufstelle erstellt wird, wird auch die Elternfunktion neu gestartet.
Zur Überwachung der Rekomposition bietet Android Studio den Layout Inspector mit dem Modus Compose Recomposition Counts. In diesem Modus zeigt jede Composable-Funktion die Anzahl der Rekompositionen und die Neustartgründe an. Dies ermöglicht es, Funktionen, die zu häufig neu komponiert werden, schnell zu finden und die Ursache zu bestimmen — instabile Parameter oder unnötige State-Abhängigkeiten.
Zusätzliche Werkzeuge: Compose Metrics (Statistikerfassung durch Instrumentierungstests) und Recomposition Timer (Messung der Ausführungszeit jeder Funktion). Google empfiehlt, diese Werkzeuge während der Profilerstellung zu aktivieren und in Release-Builds zu deaktivieren, da sie einen Overhead von bis zu 20% pro Rekomposition hinzufügen.
Bei der Analyse von Rekompositionen suchen Sie nach Mustern der unnötigen Rekomposition: eine Funktion wird neu gestartet, obwohl sich ihre Ausgabe-UI nicht ändern sollte. Eine häufige Ursache ist die Verwendung von Lambdas ohne remember, bei der jedes Mal ein neues Lambda-Objekt erstellt wird und Compose den Parameter als geändert betrachtet. Lösung: Wickeln Sie Lambdas in remember { } mit festen Captures.
// Bad: new lambda on every parent recomposition
@Composable
fun Parent() {
Child(onClick = { doSomething() }) // new lambda every time
}
// Good: remember stabilizes the lambda
@Composable
fun Parent() {
val onClick = remember { { doSomething() } }
Child(onClick = onClick) // same reference
}
Häufig gestellte Fragen
Nein, die Rekomposition ist nur die Composition-Phase. Danach werden Layout und Drawing ausgeführt. Wenn sich nach der Rekomposition die Größen und Positionen der Elemente nicht geändert haben, können Layout und Drawing vollständig übersprungen werden, was GPU-Ressourcen spart.
Bei Animationen kann die Rekomposition bis zu 120 Mal pro Sekunde laufen (120fps). Bei normaler Interaktion — 10–60 Mal pro Sekunde. Es ist wichtig, dass jede Rekomposition in das Framebudget (8–16 ms) passt, da die Anwendung sonst ruckelt.
Der Grund ist eine Parameteränderung von der Elternfunktion. Das Elternteil wird (aus eigenem Grund) neu gestartet und übergibt einen neuen Wert. Um dies zu vermeiden, überprüfen Sie die Stabilität der Parameter und verwenden Sie remember zur Stabilisierung von Lambdas und berechneten Werten.
Es gibt keine direkte Deaktivierung, aber es gibt erzwungenes Skipping über readInComposition — State wird außerhalb des Funktionskörpers gelesen, was keine Abhängigkeit registriert. Verwenden Sie dies mit Vorsicht: Die Funktion reagiert nicht auf Änderungen, was zu veralteter UI führen kann.
Composition ist teurer, da sie alle Slots und Baumknoten von Grund auf neu erstellt. Recomposition verwendet vorhandene Slots wieder und aktualisiert nur deren Werte. In der Praxis dauert die Composition eines Bildschirms 2–10 ms, während die Rekomposition eines einzelnen Elements 0.1–1 ms dauert.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch