Benutzeroberfläche für das Schreiben erstellen

In Compose ist die Benutzeroberfläche unveränderlich. Sie kann nicht mehr aktualisiert werden, nachdem sie gezeichnet. Sie können den Status Ihrer Benutzeroberfläche steuern. Jedes Mal, wenn der Status der Änderungen an der Benutzeroberfläche hat Compose die Teile der UI-Struktur neu erstellt, die geändert. Composables können „State“- und „Exposure“-Ereignissen angezeigt. Ein TextField akzeptiert z. B. einen Wert und stellt einen Callback-onValueChange, der den Callback-Handler anfordert, die Wert.

var name by remember { mutableStateOf("") }
OutlinedTextField(
    value = name,
    onValueChange = { name = it },
    label = { Text("Name") }
)

Zusammensetzbare Funktionen akzeptieren Status- und Veröffentlichungsereignisse, sodass der unidirektionale Datenfluss Muster gut zu Jetpack Compose passt. In diesem Leitfaden wird erläutert, wie Sie das Muster des unidirektionalen Datenflusses in Compose, die Implementierung von Ereignissen und wie ViewModels in Compose verwendet werden.

Unidirektionaler Datenfluss

Ein unidirektionaler Datenfluss (UDF) ist ein Designmuster, bei dem der Zustand nach unten fließt. und Ereignisse fließen in die Höhe. Wenn Sie dem unidirektionalen Datenfluss folgen, können Sie zusammensetzbare Funktionen, die in der Benutzeroberfläche den Status der Teile Ihrer App anzeigen, die und den Status ändern.

Die Aktualisierungsschleife der Benutzeroberfläche für eine Anwendung mit unidirektionalem Datenfluss sieht so aus:

  • Ereignis: In einem Teil der Benutzeroberfläche wird ein Ereignis generiert und nach oben übergeben, z. B. Schaltflächenklick, der an die zu verarbeitende ViewModel-Ressource übergeben wird; oder ein Ereignis vom andere Ebenen Ihrer App, z. B. die Angabe, dass die Nutzersitzung abgelaufen.
  • Aktualisierungsstatus: Ein Event-Handler kann den Status ändern.
  • Anzeigestatus: Der Statusinhaber übergibt den Status und die Benutzeroberfläche wird angezeigt. .

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Abbildung 1. Unidirektionaler Datenfluss.

Dieses Muster bei der Verwendung von Jetpack Compose bietet mehrere Vorteile:

  • Testbarkeit: Die Entkopplung des Status von der angezeigten UI erleichtert die Überprüfung. um beide isoliert zu testen.
  • Zustandskapselung: Da Statuswerte nur an einer Stelle aktualisiert werden können und gibt es nur eine einzige Informationsquelle für den Zustand einer zusammensetzbaren Funktion: kann es aufgrund von inkonsistenten Status zu Fehlern kommen.
  • Konsistenz der Benutzeroberfläche: Alle Statusaktualisierungen werden sofort auf der Benutzeroberfläche die Nutzung beobachtbarer Staatsinhaber wie StateFlow oder LiveData.

Unidirektionaler Datenfluss in Jetpack Compose

Zusammensetzbare Funktionen basieren auf Status und Ereignissen. Beispielsweise ist ein TextField nur aktualisiert, wenn der value-Parameter aktualisiert wird und ein onValueChange-Objekt Callback: Ein Ereignis, das die Änderung des Werts in einen neuen Wert anfordert. Verfassen definiert das State-Objekt als Werthalter und ändert den Statuswert eine Neuzusammensetzung auslösen. Sie können den Status in einer remember { mutableStateOf(value) } oder rememberSaveable { mutableStateOf(value), je nachdem, wie lange wenn wir uns den Wert merken.

Der Typ des Werts der zusammensetzbaren Funktion TextField ist String. von einem hartcodierten Wert, aus einem ViewModel oder vom Parent composable. Sie müssen sie nicht in einem State-Objekt speichern, , um den Wert zu aktualisieren, wenn onValueChange aufgerufen wird.

Zusammensetzbare Parameter definieren

Behalten Sie bei der Definition der Statusparameter einer zusammensetzbaren Funktion Folgendes bei: sollten Sie sich die folgenden Fragen stellen:

  • Wie wiederverwendbar oder flexibel ist die zusammensetzbare Funktion?
  • Wie wirken sich die Statusparameter auf die Leistung dieser zusammensetzbaren Funktion aus?

Um die Entkopplung und Wiederverwendung zu fördern, sollte jede zusammensetzbare Funktion die geringste Menge an Daten enthalten. von Informationen. Wenn Sie beispielsweise eine zusammensetzbare Funktion für die in der Kopfzeile eines Nachrichtenartikels, ziehen Sie es vor, nur die Informationen zu übergeben, die und nicht der gesamte Artikel angezeigt wird:

@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 wird durch die Verwendung einzelner Parameter auch die Leistung verbessert. Beispiel: News enthält mehr Informationen als nur title und subtitle, wenn ein neue Instanz von News an Header(news) übergeben wird, wird die zusammensetzbare Funktion neu zusammensetzen, auch wenn sich title und subtitle nicht geändert haben.

Überlegen Sie sich genau, wie viele Parameter Sie übergeben. Eine Funktion mit Zu viele Parameter verringern die Ergonomie der Funktion. Wir empfehlen, sie in einer Klasse zu gruppieren.

Ereignisse in Editor

Jede Eingabe in Ihrer App sollte als Ereignis dargestellt werden: Tippen, Textänderungen, und sogar Timer und Updates. Da sich diese Ereignisse den Status Ihrer Benutzeroberfläche ändern, ViewModel sollte derjenige sein, der sie verarbeiten und den UI-Status aktualisieren soll.

Die UI-Ebene sollte den Status nie außerhalb eines Event-Handlers ändern, da dies kann zu Inkonsistenzen und Fehlern in Ihrer Anwendung führen.

Bevorzugt die Übergabe unveränderlicher Werte für Zustands- und Event-Handler-Lambdas. Dieses -Ansatz bietet folgende Vorteile:

  • Sie verbessern die Wiederverwendbarkeit.
  • Achten Sie darauf, dass Ihre Benutzeroberfläche den Wert des Status nicht direkt ändert.
  • Sie vermeiden Nebenläufigkeitsprobleme, da Sie sicherstellen, dass der Status nicht von einem anderen Thread geändert.
  • Häufig reduzieren Sie die Codekomplexität.

So kann beispielsweise eine zusammensetzbare Funktion, die String und Lambda als Parameter akzeptiert, kann aus vielen Kontexten aufgerufen werden und ist wiederverwendbar. Angenommen, die Top-App in Ihrer App zeigt immer Text an und verfügt über eine Zurück-Schaltfläche. Sie können eine allgemeinere MyAppTopAppBar-Zusammensetzbare Funktion, die den Text und die Rückseite empfängt Ziehpunkt als Parameter:

@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.Filled.ArrowBack,
                    contentDescription = localizedString
                )
            }
        },
        // ...
    )
}

ViewModels, Status und Ereignisse: ein Beispiel

Mit ViewModel und mutableStateOf können Sie auch unidirektionale Daten einführen. in Ihrer App implementieren, wenn einer der folgenden Punkte zutrifft:

  • Der Status der UI wird über beobachtbare Statusinhaber wie StateFlow oder LiveData offengelegt.
  • ViewModel verarbeitet Ereignisse, die von der Benutzeroberfläche oder anderen Ebenen Ihrer App stammen. und aktualisiert den Inhaber des Bundesstaats basierend auf den Ereignissen.

Tippen Sie beispielsweise bei der Implementierung eines Anmeldebildschirms auf die Schaltfläche Anmelden. sollte in der App ein rotierendes Ladesymbol und ein Netzwerkanruf angezeigt werden. Wenn die die Anmeldung erfolgreich war, wechselt die App zu einem anderen Bildschirm. im Fall von Bei einem Fehler zeigt die App eine Snackbar an. So modellieren Sie den Bildschirmstatus: und das Ereignis:

Der Bildschirm hat vier Status:

  • Abgemeldet: Der Nutzer hat sich noch nicht angemeldet.
  • In Bearbeitung: wenn in der App derzeit versucht wird, den Nutzer über einen Netzwerkaufruf durchführt.
  • Fehler: bei der Anmeldung ist ein Fehler aufgetreten.
  • Angemeldet: Der Nutzer ist angemeldet.

Sie können diese Zustände als versiegelte Klasse modellieren. ViewModel stellt den Status als eine State, legt den Anfangszustand fest und aktualisiert ihn nach Bedarf. Die ViewModel verarbeitet auch das Anmeldeereignis, indem es eine onSignIn()-Methode verfügbar macht.

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