State Hoisting in Jetpack Compose – Zustand richtig herausziehen
Wer in Compose Zustand direkt in die UI packt, bekommt schwer testbare Composables. Mit State Hoisting trennst du Anzeige und Zustand sauber – wiederverwendbar und testbar.
In Jetpack Compose merkt sich ein Composable seinen Zustand mit remember und mutableStateOf. Das ist bequem – aber wenn der Zustand im Composable steckt, kannst du es weder wiederverwenden noch vernünftig testen. Die Lösung heißt State Hoisting: den Zustand nach oben ziehen und ihn als Parameter reinreichen.
Vorher: Zustand klebt in der UI
import androidx.compose.runtime.*
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Klicks: $count")
}
}Das funktioniert, ist aber fest verdrahtet: Der Button besitzt seinen Zustand.
Nachher: State Hoisting
Du teilst in zwei Composables – ein zustandsloses (nur Anzeige) und ein zustandsbehaftetes (hält den State):
import androidx.compose.runtime.*
// Zustandslos: bekommt Wert + Callback rein → wiederverwendbar & testbar
@Composable
fun CounterButton(count: Int, onIncrement: () -> Unit) {
Button(onClick = onIncrement) {
Text("Klicks: $count")
}
}
// Zustandsbehaftet: hält den State und reicht ihn nach unten
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
CounterButton(count = count, onIncrement = { count++ })
}Die Faustregel lautet „state down, events up": Der Wert fließt als Parameter nach unten, Ereignisse (Klicks) als Lambda-Callback nach oben. Das zustandslose CounterButton lässt sich jetzt in der Vorschau mit festen Werten anzeigen und im Test ohne echten State prüfen.
Warum das wichtig ist
- Wiederverwendbar: Dasselbe
CounterButtonfunktioniert überall, egal woher der Wert kommt. - Testbar: Du übergibst einfach einen festen
count– kein Framework-Zauber nötig. - Single Source of Truth: Der Zustand lebt an einer Stelle, nicht verstreut in der UI.
Bei echten Apps wandert der Zustand oft noch weiter hoch – ins ViewModel. Aber das Prinzip bleibt gleich.
Brauchst du eine saubere Android-App in Kotlin & Compose? Melde dich bei mir.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
Room-Migrationen – das Schema ändern, ohne Nutzerdaten zu verlieren
Eine neue Spalte in der Entity, und beim nächsten Start ist der Spielstand weg – weil fallbackToDestructiveMigration die Datenbank einfach löscht. So machst du es richtig, inklusive Test.
stateIn und shareIn – aus einem kalten Flow wird geteilter Zustand
Jeder Sammler eines kalten Flows startet die Arbeit neu – zwei Beobachter, zwei Datenbankabfragen. stateIn und shareIn machen daraus einen Strom, den sich alle teilen, samt aktuellem Wert und Abschalten bei Inaktivität.
viewModelScope – Coroutinen, die mit dem Bildschirm verschwinden
Eine Coroutine, die nach dem Schließen des Bildschirms weiterläuft, schreibt in ein ViewModel, das niemand mehr sieht – und hält im schlimmsten Fall die ganze Activity im Speicher. viewModelScope beendet sie automatisch.