MutableState — beobachtbarer Zustand und Aktualisierungsmechanismus in Compose

Autor: IT Sectr Veröffentlicht: 2026-06-28 Lesezeit: 7 Min.

MutableState ist eine Schnittstelle in Jetpack Compose, die einen Container für einen veränderlichen beobachtbaren Wert darstellt. Sie ist die Grundlage des reaktiven Systems von Compose: Jedes Mal, wenn sich der Wert von MutableState über den Setter ändert, benachrichtigt Compose Runtime alle lesenden Komponenten und löst eine Neuzusammensetzung aus. Laut Google Android Developers, 2026 ist das Verständnis von MutableState für die korrekte Arbeit mit Zustand in einer deklarativen UI zwingend erforderlich.

Wichtigste Punkte

  • MutableState — compose.runtime-Schnittstelle mit einer einzelnen value-Eigenschaft (Getter + Setter)
  • State — schreibgeschützte Eltern-Schnittstelle, MutableState fügt Schreibfähigkeit hinzu
  • Neuzusammensetzung wird beim Aufruf des value-Setters innerhalb eines aktiven Snapshot-Zyklus ausgelöst
  • SnapshotMutationPolicy bestimmt, wann eine Änderung als signifikant für die Neuzusammensetzung gilt
  • MutableIntState und ähnliche — optimierte primitive Versionen von MutableState

Was ist MutableState in Jetpack Compose

MutableState ist eine Schnittstelle aus dem Paket androidx.compose.runtime, die eine einzelne Eigenschaft deklariert: override var value: T. Der Getter gibt den aktuellen Wert zurück, der Setter schreibt einen neuen und benachrichtigt Compose Runtime über die Änderung. Die Schnittstelle erbt von State<T>, bei dem value schreibgeschützt ist. Diese zweistufige Architektur ermöglicht eine Zugriffstrennung: Eine Komponente, die nur den Wert lesen muss, erhält State<T>, während die Eigentümer-Komponente MutableState<T> erhält.

Die Standardimplementierung von MutableState ist die interne Klasse SnapshotMutableStateImpl, die einen Snapshot-Mechanismus zur Verfolgung von Änderungen verwendet. Wenn der value-Setter aufgerufen wird, zeichnet der aktuelle Snapshot den Schreibvorgang auf und markiert alle registrierten ObservedScope als ungültig. Diese Bereiche (normalerweise Composable-Funktionen) werden im nächsten Frame neu zusammengesetzt. Der gesamte Prozess erfolgt synchron und ohne Sperren dank der Lock-free Snapshot-Architektur.

State vs MutableState: State ist eine schreibgeschützte Schnittstelle, die für öffentliche Komponenten-APIs verwendet wird. Wenn Sie einen Composable-Funktionsparameter als State<Int> deklarieren, garantieren Sie, dass die Komponente den Zustand lesen, aber nicht ändern kann. MutableState wird innerhalb der Eigentümer-Komponente verwendet. Diese Trennung ist eine der grundlegenden Compose-Praktiken, die unbefugte Änderungen verhindert.

Hierarchie von State, MutableState und abgeleiteten Schnittstellen

Die Hierarchie der Zustandsschnittstellen in Compose hat mehrere Ebenen. An der Spitze steht State<T> mit einem schreibgeschützten value. Darunter befindet sich MutableState<T> mit einem lese-schreibbaren value. Weiter unten folgen spezialisierte primitive Versionen: MutableIntState, MutableFloatState, MutableLongState, MutableBooleanState und andere, die das Boxing von Primitiven vermeiden.

MutableDoubleState und MutableLongState sind weniger verbreitet, aber ebenfalls vorhanden. Sammlungs-Schnittstellen: MutableListState — zur Verfolgung von Änderungen innerhalb einer Liste, MutableStateMap — für Maps. Jede dieser Schnittstellen ist für ein bestimmtes Szenario optimiert und erweitert das grundlegende MutableState um zusätzliche Methoden zur Sammlungsmanipulation.

SnapshotStateList und SnapshotStateMap sind Implementierungen von veränderlichen Listen und Maps, die mit Snapshots kompatibel sind. Sie ermöglichen nicht nur die Verfolgung von Wertersetzungen, sondern auch von internen Änderungen: Hinzufügen eines Elements zu einer Liste, Entfernen, Ändern eines vorhandenen Elements. Für solche Strukturen erstellen mutableStateListOf() und mutableStateMapOf() die entsprechenden beobachtbaren Sammlungen.

SchnittstelleZweckErstellungsmethode
State<T>Schreibgeschützter Container
MutableState<T>Lese-Schreib-ContainermutableStateOf()
MutableIntStatePrimitiver Int ohne BoxingmutableIntStateOf()
MutableFloatStatePrimitiver Float ohne BoxingmutableFloatStateOf()
SnapshotStateListBeobachtbare ListemutableStateListOf()
SnapshotStateMapBeobachtbare MapmutableStateMapOf()

SnapshotMutationPolicy: Wann die Neuzusammensetzung ausgelöst wird

SnapshotMutationPolicy ist eine Schnittstelle, die bestimmt, wann eine Änderung von MutableState als signifikant gilt. mutableStateOf akzeptiert policy als zweites Argument. Standardimplementierungen: structuralEquality() (equals), referentialEquality() (===), neverEqualPolicy() (betrachtet Änderungen immer als signifikant). Für benutzerdefinierte Logik kann eine eigene Richtlinie implementiert werden.

structuralEquality() — Standardverhalten. Compose vergleicht den neuen Wert mit dem alten über equals(). Wenn das Ergebnis true ist, wird die Neuzusammensetzung NICHT ausgelöst. Dies ist praktisch für Primitive und Data Classes, bei denen zwei Instanzen mit denselben Feldern als gleich betrachtet werden. Problem: Wenn eine Data Class eine List enthält, führt equals() einen tiefen Vergleich durch, der bei großen Listen kostspielig sein kann.

referentialEquality() — vergleicht Referenzen über ===. Die Neuzusammensetzung wird nur ausgelöst, wenn ein anderes Objekt zugewiesen wird, selbst wenn der Inhalt identisch ist. Dies ist optimal für unveränderliche Data Classes, bei denen jede neue Instanz eine Änderung garantiert. neverEqualPolicy() — betrachtet Änderungen immer als signifikant, ohne einen Vergleich durchzuführen. Nützlich, wenn der Setter selten aufgerufen wird und keine Zeit für equals aufgewendet werden muss.

kotlin
    // Policy comparison in practice
data class User(val name: String, val age: Int)

@Composable
fun UserProfile() {
    // structuralEquality: recomposition ONLY if data changed
    var user1 by remember {
        mutableStateOf(User("Alice", 30))
    }

    // referentialEquality: recomposition on ANY assignment
    var user2 by remember {
        mutableStateOf(User("Bob", 25),
            SnapshotMutationPolicy.referentialEquality())
    }

    // user1: copy() with same fields does NOT trigger recomposition
    // user2: even user2.copy() == user2 triggers recomposition (new ref)
}

Primitive State: MutableIntState, MutableFloatState, MutableLongState

Primitive MutableIntState und ähnliche sind spezialisierte Schnittstellen, die Primitive ohne Boxing speichern. Ein normaler MutableState<Int> speichert Int als Integer, was bei jedem Schreibvorgang ein Objekt auf dem Heap erzeugt. MutableIntState speichert int (primitiv) und eliminiert damit vollständig den Boxing-Overhead. Dies ist besonders wichtig bei hochfrequenten Aktualisierungen — Zähler, Scroll-Positionen, Animationswerte.

mutableIntStateOf(), mutableFloatStateOf(), mutableLongStateOf() — Funktionen, die primitive MutableState erstellen. Die Schnittstellen heißen MutableIntState, MutableFloatState, MutableLongState. Sie erweitern MutableState<Int>, MutableState<Float> bzw. MutableState<Long> und fügen die Eigenschaft intValue für den schnellen Zugriff auf das Primitiv hinzu. Ihre interne Implementierung verwendet AtomicInteger für sperrfreies Lesen/Schreiben.

Verwendung: Zähler (Int), Scroll-Positionen (Float offset), Zeitstempel (Long). In den meisten alltäglichen Szenarien ist der Leistungsunterschied nicht wahrnehmbar, aber in LazyList mit Tausenden von Elementen und Übergangsanimationen bieten primitive State eine spürbare Verbesserung. Google empfiehlt die Verwendung von primitiven State für typische Szenarien anstelle des universellen mutableStateOf.

kotlin
@Composable
fun ScrollCounter() {
    // Bad: boxing on every update
    var badCount by remember { mutableStateOf(0) }

    // Good: no boxing, primitive storage
    var goodCount by remember { mutableIntStateOf(0) }

    // Usage is identical
    Button(onClick = { goodCount++ }) {
        Text("Count: $goodCount")
    }
}

Praktische Beispiele für die Arbeit mit MutableState

Betrachten wir eine TodoList-Komponente, bei der MutableState in zwei Formen verwendet wird: als separate Variablen für den Eingabezustand und als SnapshotStateList für eine dynamische Aufgabenliste. Beide verwenden Delegation zur Code-Verkürzung.

kotlin
data class TodoItem(val id: Int, val text: String, val isDone: Boolean = false)

@Composable
fun TodoScreen() {
    var inputText by remember { mutableStateOf("") }
    val items = remember { mutableStateListOf() }

    Column(modifier = Modifier.padding(16.dp)) {
        Row {
            TextField(
                value = inputText,
                onValueChange = { inputText = it }
            )
            Button(onClick = {
                if (inputText.isNotBlank()) {
                    items.add(TodoItem(items.size, inputText))
                    inputText = ""
                }
            }) { Text("Add") }
        }

        LazyColumn {
            items(items) { item ->
                Row(modifier = Modifier.fillMaxWidth().clickable {
                    val idx = items.indexOf(item)
                    items[idx] = item.copy(isDone = !item.isDone)
                }) {
                    Checkbox(checked = item.isDone, onCheckedChange = null)
                    Text(item.text)
                }
            }
        }
    }
}

mutableStateListOf erstellt eine SnapshotStateList — eine veränderliche Liste, die Änderungen einzelner Elemente verfolgt. Wenn items.add() und items[n] = newValue aufgerufen werden, sieht Compose die Mutation und setzt nur diejenigen LazyColumn-Elemente neu zusammen, die sich geändert haben. inputText ist ein normaler MutableState<String>. Die Kombination zweier MutableState-Typen (einzeln und Sammlung) ist ein typisches Muster für Bildschirme mit Formularen und Listen.

Häufig gestellte Fragen

Kann ich MutableState ohne remember verwenden?

MutableState ohne remember wird bei jeder Neuzusammensetzung neu erstellt. Jeder neue Aufruf von mutableStateOf erzeugt ein neues Objekt und der alte Wert geht verloren. Verwenden Sie immer remember, um den State zwischen Neuzusammensetzungen zu erhalten, es sei denn, der State wird außerhalb eines Composable erstellt (z. B. in einem ViewModel).

Wie konvertiere ich MutableState in eine normale Variable?

Lesen Sie .value einmal außerhalb eines Snapshots über snapshot { }. Dies deaktiviert jedoch die Reaktivität — Änderungen lösen keine Neuzusammensetzung mehr aus. Für einmaliges Lesen ohne Abonnement verwenden Sie currentValue() innerhalb eines Snapshots ohne Lesen.

Was ist schneller: mutableStateOf oder mutableIntStateOf?

mutableIntStateOf ist schneller, da es kein Boxing von int in Integer erfordert. Bei Tausenden von Aktualisierungen pro Sekunde (Animation, Scrollen) kann der Unterschied 30-50% der Zuordnungszeit betragen. Bei seltenen Aktualisierungen (Klicks, Texteingabe) ist der Unterschied vernachlässigbar.

Kann MutableState als Argument einer Composable-Funktion verwendet werden?

Es ist möglich, aber nicht empfohlen. Übergeben Sie statt MutableState State (schreibgeschützt) + einen onValueChange-Lambda. Dies implementiert das State-Hoisting-Muster und macht die Komponente wiederverwendbar. Komponenten, die MutableState akzeptieren, verletzen den unidirektionalen Datenfluss.

Wie erstelle ich eine benutzerdefinierte MutableState-Implementierung?

Implementieren Sie die MutableState-Schnittstelle und stellen Sie override var value mit einem Getter und Setter bereit. Im Setter können Sie Validierung oder Protokollierung hinzufügen. Für die Abwärtskompatibilität mit Compose Runtime wickeln Sie Ihre benutzerdefinierte Implementierung in snapshotFlow ein oder verwenden Sie snapshotIncrement.

Zusammenfassung

  • MutableState — grundlegende Schnittstelle für veränderlichen beobachtbaren Zustand in Compose
  • State — schreibgeschützte Version zum Übergeben von Daten ohne Änderungsrecht
  • SnapshotMutationPolicy verwaltet die Bedingungen für die Auslösung der Neuzusammensetzung bei Änderung
  • Primitive State (MutableIntState u. a.) beseitigen Boxing-Overhead
  • SnapshotStateList und SnapshotStateMap verfolgen interne Sammlungsänderungen
  • Neuzusammensetzung wird bei jedem Setter-Aufruf von value automatisch ausgelöst
  • Empfehlung: Verwenden Sie MutableState zum Besitzen von Zustand und State zum Weitergeben

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.

Projekt besprechen

Lesen Sie auch