In Compose ist die Benutzeroberfläche unveränderlich. Sie kann nach dem Zeichnen nicht mehr aktualisiert werden. Sie können jedoch den Status Ihrer Benutzeroberfläche steuern. Jedes Mal, wenn sich der Status der Benutzeroberfläche ändert, erstellt Compose die geänderten Teile des UI-Baums neu. Composables können Status akzeptieren und Ereignisse freigeben. Beispiel: Ein TextField
akzeptiert einen Wert und gibt einen Rückruf onValueChange
aus, der den Rückruf-Handler auffordert, den Wert zu ändern.
var name by remember { mutableStateOf("") } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } )
Da Compose-Komponenten Status akzeptieren und Ereignisse freigeben, passt das Muster für den unidirektionalen Datenfluss gut zu Jetpack Compose. In diesem Leitfaden erfahren Sie, wie Sie das unidirektionale Datenflussmuster in Compose implementieren, Ereignisse und Statushalter implementieren und mit ViewModels in Compose arbeiten.
Einseitiger Datenfluss
Ein einseitiger Datenfluss (UDF) ist ein Designmuster, bei dem der Status nach unten und Ereignisse nach oben fließen. Wenn Sie einen unidirektionalen Datenfluss verwenden, können Sie Composeables, die den Status in der Benutzeroberfläche anzeigen, von den Teilen Ihrer App entkoppeln, die den Status speichern und ändern.
Die UI-Aktualisierungsschleife für eine App mit unidirektionalem Datenfluss sieht so aus:
- Ereignis: Ein Teil der Benutzeroberfläche generiert ein Ereignis und leitet es weiter, z. B. ein Klick auf eine Schaltfläche, der an das ViewModel zur Verarbeitung übergeben wird. Ein Ereignis kann auch von anderen Ebenen Ihrer App übergeben werden, z. B. um anzugeben, dass die Nutzersitzung abgelaufen ist.
- Status aktualisieren: Ein Ereignishandler kann den Status ändern.
- Displaystatus: Der Statushalter gibt den Status weiter und die Benutzeroberfläche zeigt ihn an.

Wenn Sie bei der Verwendung von Jetpack Compose diesem Muster folgen, ergeben sich mehrere Vorteile:
- Testbarkeit: Wenn der Status von der Benutzeroberfläche getrennt wird, auf der er angezeigt wird, lässt sich beides leichter einzeln testen.
- Statuskapselung: Da der Status nur an einer Stelle aktualisiert werden kann und es nur eine einzige Quelle für den Status eines Composeables gibt, ist es weniger wahrscheinlich, dass Sie aufgrund inkonsistenter Status Fehler verursachen.
- UI-Konsistenz: Alle Statusaktualisierungen werden durch die Verwendung von beobachtbaren Statushaltern wie
StateFlow
oderLiveData
sofort in der Benutzeroberfläche angezeigt.
Einseitiger Datenfluss in Jetpack Compose
Composables basieren auf Status und Ereignissen. Ein TextField
wird beispielsweise nur aktualisiert, wenn sein value
-Parameter aktualisiert wird und ein onValueChange
-Callback vorhanden ist, also ein Ereignis, bei dem der Wert in einen neuen geändert werden soll. Mit „Compose“ wird das State
-Objekt als Werthalter definiert. Änderungen am Statuswert lösen eine Neuzusammensetzung aus. Sie können den Status in einem remember { mutableStateOf(value) }
oder einem rememberSaveable { mutableStateOf(value)
speichern, je nachdem, wie lange der Wert gespeichert werden muss.
Der Wert des TextField
-Composables hat den Typ String
. Er kann also von überall stammen – von einem hartcodierten Wert, von einem ViewModel oder vom übergeordneten Composable übergeben werden. Sie müssen ihn nicht in einem State
-Objekt speichern, aber Sie müssen den Wert aktualisieren, wenn onValueChange
aufgerufen wird.
Zusammensetzbare Parameter definieren
Beachten Sie beim Definieren der Statusparameter eines Composeables Folgendes:
- Wie wiederverwendbar oder flexibel ist das Composeable?
- Wie wirken sich die Statusparameter auf die Leistung dieses Composeables aus?
Um die Entkopplung und Wiederverwendung zu fördern, sollte jedes Composeable möglichst wenig Informationen enthalten. Wenn du beispielsweise ein Composeable erstellst, das den Titel eines Nachrichtenartikels enthalten soll, solltest du nur die Informationen übergeben, die angezeigt werden sollen, und nicht den gesamten Artikel:
@Composable fun Header(title: String, subtitle: String) { // Recomposes when title or subtitle have changed. } @Composable fun Header(news: News) { // Recomposes when a new instance of News is passed in. }
Manchmal lässt sich die Leistung auch durch die Verwendung einzelner Parameter verbessern. Wenn News
beispielsweise mehr Informationen als nur title
und subtitle
enthält, wird das Composeable jedes Mal neu erstellt, wenn eine neue Instanz von News
an Header(news)
übergeben wird, auch wenn sich title
und subtitle
nicht geändert haben.
Überlegen Sie sich gut, wie viele Parameter Sie übergeben. Eine Funktion mit zu vielen Parametern verringert die Ergonomie der Funktion. In diesem Fall ist es daher besser, sie in einer Klasse zu gruppieren.
Ereignisse in Compose
Jede Eingabe in Ihre App sollte als Ereignis dargestellt werden: Tippen, Textänderungen und sogar Timer oder andere Aktualisierungen. Da diese Ereignisse den Status Ihrer Benutzeroberfläche ändern, sollte die ViewModel
diese Ereignisse verarbeiten und den UI-Status aktualisieren.
Der Status der UI-Ebene sollte niemals außerhalb eines Ereignis-Handlers geändert werden, da dies zu Inkonsistenzen und Fehlern in Ihrer Anwendung führen kann.
Geben Sie für Status- und Ereignishandler-Lambdas vorzugsweise unveränderliche Werte weiter. Dieser Ansatz bietet folgende Vorteile:
- Sie verbessern die Wiederverwendbarkeit.
- Sie sorgen dafür, dass der Wert des Status nicht direkt über die Benutzeroberfläche geändert wird.
- Sie vermeiden Probleme mit der Parallelität, da Sie dafür sorgen, dass der Status nicht von einem anderen Thread verändert wird.
- Oft wird dadurch die Codekomplexität reduziert.
Ein Composeable, das beispielsweise eine String
und ein Lambda als Parameter akzeptiert, kann aus vielen Kontexten aufgerufen werden und ist sehr wiederverwendbar. Angenommen, die obere App-Leiste in Ihrer App enthält immer Text und eine Schaltfläche „Zurück“. Sie können ein allgemeineres MyAppTopAppBar
-Komposit definieren, das den Text und den Handle der Schaltfläche „Zurück“ als Parameter empfängt:
@Composable fun MyAppTopAppBar(topAppBarText: String, onBackPressed: () -> Unit) { TopAppBar( title = { Text( text = topAppBarText, textAlign = TextAlign.Center, modifier = Modifier .fillMaxSize() .wrapContentSize(Alignment.Center) ) }, navigationIcon = { IconButton(onClick = onBackPressed) { Icon( Icons.AutoMirrored.Filled.ArrowBack, contentDescription = localizedString ) } }, // ... ) }
ViewModels, Status und Ereignisse: ein Beispiel
Mit ViewModel
und mutableStateOf
können Sie auch einen unidirektionalen Datenfluss in Ihrer App einrichten, wenn eines der folgenden Kriterien erfüllt ist:
- Der Status Ihrer Benutzeroberfläche wird über beobachtbare Statushalter wie
StateFlow
oderLiveData
freigegeben. - Der
ViewModel
verarbeitet Ereignisse, die von der Benutzeroberfläche oder anderen Ebenen Ihrer App stammen, und aktualisiert den Statushalter basierend auf den Ereignissen.
Wenn Sie beispielsweise einen Anmeldebildschirm implementieren, sollte durch Tippen auf die Schaltfläche Anmelden in Ihrer App ein Fortschrittskreisel und ein Netzwerkaufruf angezeigt werden. Wenn die Anmeldung erfolgreich war, wird in Ihrer App ein anderer Bildschirm angezeigt. Bei einem Fehler wird eine Snackbar angezeigt. So modellieren Sie den Bildschirmstatus und das Ereignis:
Der Bildschirm hat vier Status:
- Abgemeldet: Der Nutzer ist noch nicht angemeldet.
- In Bearbeitung: Ihre App versucht derzeit, den Nutzer durch einen Netzwerkaufruf anzumelden.
- Fehler: Bei der Anmeldung ist ein Fehler aufgetreten.
- Angemeldet: Der Nutzer ist angemeldet.
Sie können diese Status als versiegelte Klasse modellieren. Die ViewModel
stellt den Status als State
bereit, legt den Anfangsstatus fest und aktualisiert den Status nach Bedarf. Die ViewModel
verarbeitet auch das Anmeldeereignis, indem eine onSignIn()
-Methode freigegeben wird.
class MyViewModel : ViewModel() { private val _uiState = mutableStateOf<UiState>(UiState.SignedOut) val uiState: State<UiState> get() = _uiState // ... }
Zusätzlich zur mutableStateOf
API bietet Compose Erweiterungen für LiveData
, Flow
und Observable
, um sich als Listener zu registrieren und den Wert als Status darzustellen.
class MyViewModel : ViewModel() { private val _uiState = MutableLiveData<UiState>(UiState.SignedOut) val uiState: LiveData<UiState> get() = _uiState // ... } @Composable fun MyComposable(viewModel: MyViewModel) { val uiState = viewModel.uiState.observeAsState() // ... }
Weitere Informationen
Weitere Informationen zur Architektur in Jetpack Compose finden Sie in den folgenden Ressourcen:
Produktproben
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Zustand und Jetpack Compose
- UI-Status in „Schreiben“ speichern
- Nutzereingabe verarbeiten