Im Leitfaden zur UI-Ebene wird der unidirektionale Datenfluss (UDF) als Methode zum Erstellen und Verwalten des UI-Zustands für die UI-Ebene beschrieben.

Außerdem werden die Vorteile der Delegierung der UDF-Verwaltung an eine spezielle Klasse namens „State Holder“ hervorgehoben. Sie können einen Status-Holder entweder über eine ViewModel
oder eine einfache Klasse implementieren. In diesem Dokument werden State-Holder und ihre Rolle in der UI-Schicht genauer betrachtet.
Am Ende dieses Dokuments sollten Sie wissen, wie Sie den Anwendungsstatus in der UI-Schicht verwalten, d. h. die Pipeline für die Erstellung des UI-Status. Sie sollten Folgendes verstehen und wissen:
- Informationen zu den Arten von UI-Status, die in der UI-Schicht vorhanden sind
- Logiktypen, die in der UI-Schicht für diese UI-Zustände ausgeführt werden
- Sie wissen, wie Sie die richtige Implementierung eines State Holders auswählen, z. B.
ViewModel
oder eine Klasse.
Elemente der Produktionspipeline für den UI-Zustand
Der UI-Zustand und die Logik, mit der er erzeugt wird, definieren die UI-Ebene.
UI-Status
UI-Zustand ist die Eigenschaft, die die Benutzeroberfläche beschreibt. Es gibt zwei Arten von UI-Status:
- Der UI-Status des Displays gibt an, was auf dem Display angezeigt werden muss. Eine
NewsUiState
-Klasse kann beispielsweise die Nachrichtenartikel und andere Informationen enthalten, die zum Rendern der Benutzeroberfläche erforderlich sind. Dieser Status ist in der Regel mit anderen Ebenen der Hierarchie verbunden, da er App-Daten enthält. - Der Status von UI-Elementen bezieht sich auf Eigenschaften, die UI-Elementen innewohnen und die beeinflussen, wie sie gerendert werden. Ein UI-Element kann ein- oder ausgeblendet werden und eine bestimmte Schriftart, Schriftgröße oder Schriftfarbe haben. In Android Views wird dieser Status von der View selbst verwaltet, da sie von Natur aus zustandsbehaftet ist. Es werden Methoden zum Ändern oder Abfragen des Status bereitgestellt. Ein Beispiel dafür sind die Methoden
get
undset
der KlasseTextView
für ihren Text. In Jetpack Compose ist der Status extern vom Composable. Sie können ihn sogar aus der unmittelbaren Nähe des Composables in die aufrufende Composable-Funktion oder einen State Holder verschieben. Ein Beispiel dafür istScaffoldState
für die zusammensetzbare FunktionScaffold
.
Logik
Der UI-Status ist keine statische Eigenschaft, da sich der UI-Status im Laufe der Zeit aufgrund von Anwendungsdaten und Nutzerereignissen ändert. Die Logik bestimmt die Einzelheiten der Änderung, einschließlich der Teile des UI-Zustands, die sich geändert haben, warum sie sich geändert haben und wann sie sich ändern sollen.

Die Logik in einer Anwendung kann entweder Geschäftslogik oder UI-Logik sein:
- Die Geschäftslogik ist die Implementierung von Produktanforderungen für App-Daten. Beispiel: Ein Artikel wird in einer Newsreader-App mit einem Lesezeichen versehen, wenn der Nutzer auf die Schaltfläche tippt. Diese Logik zum Speichern eines Lesezeichens in einer Datei oder Datenbank befindet sich in der Regel in den Domain- oder Datenschichten. Der State Holder delegiert diese Logik in der Regel an diese Ebenen, indem er die von ihnen bereitgestellten Methoden aufruft.
- Die UI-Logik bezieht sich darauf, wie der UI-Status auf dem Bildschirm angezeigt wird. Beispiele hierfür sind das Abrufen des richtigen Hinweises für die Suchleiste, wenn der Nutzer eine Kategorie ausgewählt hat, das Scrollen zu einem bestimmten Element in einer Liste oder die Navigationslogik zu einem bestimmten Bildschirm, wenn der Nutzer auf eine Schaltfläche klickt.
Android-Lebenszyklus und die Arten von UI-Zustand und ‑Logik
Die UI-Ebene besteht aus zwei Teilen: einem, der vom UI-Lebenszyklus abhängig ist, und einem, der unabhängig davon ist. Durch diese Trennung werden die Datenquellen für die einzelnen Teile festgelegt. Daher sind unterschiedliche Arten von UI-Status und ‑Logik erforderlich.
- Unabhängig vom UI-Lebenszyklus: Dieser Teil der UI-Ebene befasst sich mit den datenerzeugenden Ebenen der App (Daten- oder Domänenebenen) und wird durch die Geschäftslogik definiert. Der Lebenszyklus, Konfigurationsänderungen und die Neuerstellung von
Activity
in der Benutzeroberfläche können sich darauf auswirken, ob die Pipeline für die Erstellung des UI-Status aktiv ist. Sie haben jedoch keinen Einfluss auf die Gültigkeit der erstellten Daten. - UI-Lebenszyklusabhängig: Dieser Teil der UI-Ebene befasst sich mit der UI-Logik und wird direkt von Änderungen des Lebenszyklus oder der Konfiguration beeinflusst. Diese Änderungen wirken sich direkt auf die Gültigkeit der darin gelesenen Datenquellen aus. Daher kann sich der Status nur ändern, wenn der Lebenszyklus aktiv ist. Beispiele hierfür sind Laufzeitberechtigungen und das Abrufen von konfigurationsabhängigen Ressourcen wie lokalisierten Strings.
Das lässt sich in der folgenden Tabelle zusammenfassen:
Unabhängig vom UI-Lebenszyklus | UI-Lebenszyklusabhängig |
---|---|
Geschäftslogik | UI-Logik |
UI-Status des Displays |
Die Pipeline für die Zustandsproduktion in der UI
Die Pipeline zur Erstellung des UI-Zustands bezieht sich auf die Schritte, die zur Erstellung des UI-Zustands erforderlich sind. Diese Schritte umfassen die Anwendung der zuvor definierten Logiktypen und hängen vollständig von den Anforderungen Ihrer Benutzeroberfläche ab. Einige Benutzeroberflächen können sowohl von UI‑Lifecycle-unabhängigen als auch von UI‑Lifecycle-abhängigen Teilen der Pipeline profitieren, entweder oder keines von beiden.
Die folgenden Permutationen der UI-Layer-Pipeline sind also gültig:
Der UI-Zustand wird von der UI selbst erstellt und verwaltet. Ein einfaches, wiederverwendbares Basis-Counter-Beispiel:
@Composable fun Counter() { // The UI state is managed by the UI itself var count by remember { mutableStateOf(0) } Row { Button(onClick = { ++count }) { Text(text = "Increment") } Button(onClick = { --count }) { Text(text = "Decrement") } } }
UI-Logik → UI Sie können beispielsweise eine Schaltfläche einblenden oder ausblenden, mit der ein Nutzer zum Anfang einer Liste springen kann.
@Composable fun ContactsList(contacts: List<Contact>) { val listState = rememberLazyListState() val isAtTopOfList by remember { derivedStateOf { listState.firstVisibleItemIndex < 3 } } // Create the LazyColumn with the lazyListState ... // Show or hide the button (UI logic) based on the list scroll position AnimatedVisibility(visible = !isAtTopOfList) { ScrollToTopButton() } }
Geschäftslogik → Benutzeroberfläche Ein UI-Element, das das Foto des aktuellen Nutzers auf dem Bildschirm anzeigt.
@Composable fun UserProfileScreen(viewModel: UserProfileViewModel = hiltViewModel()) { // Read screen UI state from the business logic state holder val uiState by viewModel.uiState.collectAsStateWithLifecycle() // Call on the UserAvatar Composable to display the photo UserAvatar(picture = uiState.profilePicture) }
Geschäftslogik → UI-Logik → UI. Ein UI-Element, das gescrollt wird, um die richtigen Informationen für einen bestimmten UI-Status auf dem Bildschirm anzuzeigen.
@Composable fun ContactsList(viewModel: ContactsViewModel = hiltViewModel()) { // Read screen UI state from the business logic state holder val uiState by viewModel.uiState.collectAsStateWithLifecycle() val contacts = uiState.contacts val deepLinkedContact = uiState.deepLinkedContact val listState = rememberLazyListState() // Create the LazyColumn with the lazyListState ... // Perform UI logic that depends on information from business logic if (deepLinkedContact != null && contacts.isNotEmpty()) { LaunchedEffect(listState, deepLinkedContact, contacts) { val deepLinkedContactIndex = contacts.indexOf(deepLinkedContact) if (deepLinkedContactIndex >= 0) { // Scroll to deep linked item listState.animateScrollToItem(deepLinkedContactIndex) } } } }
Wenn beide Arten von Logik auf die Pipeline zur Erstellung des UI-Zustands angewendet werden, muss die Geschäftslogik immer vor der UI-Logik angewendet werden. Wenn Sie versuchen, Geschäftslogik nach der UI-Logik anzuwenden, würde das bedeuten, dass die Geschäftslogik von der UI-Logik abhängt. In den folgenden Abschnitten wird erläutert, warum dies ein Problem ist. Dazu werden verschiedene Logiktypen und ihre Statusinhaber genauer betrachtet.

Staatliche Stellen und ihre Zuständigkeiten
Die Aufgabe eines State-Holders besteht darin, den Status so zu speichern, dass die App ihn lesen kann. Wenn Logik erforderlich ist, fungiert es als Vermittler und bietet Zugriff auf die Datenquellen, die die erforderliche Logik enthalten. Auf diese Weise delegiert der State-Holder die Logik an die entsprechende Datenquelle.
Das bietet folgende Vorteile:
- Einfache UIs: Die UI bindet nur ihren Status.
- Wartungsfreundlichkeit: Die im State Holder definierte Logik kann iteriert werden, ohne dass die Benutzeroberfläche selbst geändert werden muss.
- Testbarkeit: Die Benutzeroberfläche und die Logik für die Statusgenerierung können unabhängig voneinander getestet werden.
- Lesbarkeit: Leser des Codes können die Unterschiede zwischen dem Code für die UI-Darstellung und dem Code für die UI-Statusproduktion deutlich erkennen.
Unabhängig von Größe oder Umfang hat jedes UI-Element eine 1:1-Beziehung zum entsprechenden State Holder. Außerdem muss ein State Holder jede Nutzeraktion akzeptieren und verarbeiten können, die zu einer Änderung des UI-Status führen könnte, und die entsprechende Statusänderung vornehmen.
Arten von Statusinhabern
Ähnlich wie bei den Arten von UI-Zustand und ‑Logik gibt es in der UI-Schicht zwei Arten von State-Holdern, die durch ihre Beziehung zum UI-Lebenszyklus definiert werden:
- Der Statusinhaber der Geschäftslogik.
- Der State Holder für die UI-Logik.
In den folgenden Abschnitten werden die verschiedenen Arten von State-Holdern genauer betrachtet, beginnend mit dem State-Holder für die Geschäftslogik.
Geschäftslogik und ihr Statusinhaber
Status-Holder für die Geschäftslogik verarbeiten Nutzerereignisse und wandeln Daten aus den Daten- oder Domänenebenen in den UI-Status des Bildschirms um. Um eine optimale Nutzererfahrung zu bieten, wenn der Android-Lebenszyklus und Änderungen an der App-Konfiguration berücksichtigt werden, sollten Status-Holder, die Geschäftslogik verwenden, die folgenden Eigenschaften haben:
Attribut | Details |
---|---|
Erzeugt UI-Zustand | Die Inhaber des Zustands der Geschäftslogik sind für die Erstellung des UI-Zustands für ihre Benutzeroberflächen verantwortlich. Dieser UI-Status ist oft das Ergebnis der Verarbeitung von Nutzerereignissen und des Lesens von Daten aus der Domain- und der Datenschicht. |
Durch die Neuerstellung von Aktivitäten beibehalten | Die Statusinhaber der Geschäftslogik behalten ihren Status und ihre Pipelines für die Statusverarbeitung über die Activity -Neuerstellung hinweg bei, was zu einer nahtlosen Nutzererfahrung beiträgt. Wenn der Statusinhaber nicht beibehalten werden kann und neu erstellt wird (normalerweise nach Prozessende), muss er seinen letzten Status einfach wiederherstellen können, um eine konsistente Nutzererfahrung zu gewährleisten. |
Langlebiger Status | Statusinhaber für die Geschäftslogik werden häufig verwendet, um den Status für Navigationsziele zu verwalten. Daher behalten sie ihren Status oft bei Navigationsänderungen bei, bis sie aus dem Navigationsdiagramm entfernt werden. |
Ist für die jeweilige Benutzeroberfläche eindeutig und kann nicht wiederverwendet werden | Inhabern von Geschäftslogikstatus wird in der Regel der Status für eine bestimmte App-Funktion, z. B. TaskEditViewModel oder TaskListViewModel , zugewiesen. Sie sind daher immer nur für diese App-Funktion anwendbar. Derselbe Status-Holder kann diese App-Funktionen auf verschiedenen Formfaktoren unterstützen. Beispielsweise können mobile, TV- und Tablet-Versionen der App denselben Status-Holder für die Geschäftslogik verwenden. |
Sehen Sie sich beispielsweise das Navigationsziel des Autors in der App Now in Android an:

Als Inhaber des Geschäftslogikstatus erzeugt AuthorViewModel
in diesem Fall den UI-Status:
@HiltViewModel
class AuthorViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
private val authorsRepository: AuthorsRepository,
newsRepository: NewsRepository
) : ViewModel() {
val uiState: StateFlow<AuthorScreenUiState> = …
// Business logic
fun followAuthor(followed: Boolean) {
…
}
}
Beachten Sie, dass das AuthorViewModel
die oben beschriebenen Attribute hat:
Attribut | Details |
---|---|
Erzeugt AuthorScreenUiState |
Der AuthorViewModel liest Daten aus dem AuthorsRepository und dem NewsRepository und verwendet diese Daten, um AuthorScreenUiState zu erstellen. Außerdem wird Geschäftslogik angewendet, wenn der Nutzer einem Author folgen oder die Funktion zum Folgen eines Author beenden möchte, indem er die Anfrage an AuthorsRepository delegiert. |
Hat Zugriff auf die Datenschicht | Eine Instanz von AuthorsRepository und NewsRepository wird im Konstruktor übergeben, sodass die Geschäftslogik zum Folgen eines Author implementiert werden kann. |
Hält Activity -Aktivitäten stand |
Da es mit einem ViewModel implementiert wird, bleibt es auch bei einer schnellen Activity -Neuerstellung erhalten. Wenn der Prozess beendet wird, kann das SavedStateHandle -Objekt gelesen werden, um die Mindestmenge an Informationen bereitzustellen, die zum Wiederherstellen des UI-Zustands aus der Datenschicht erforderlich sind. |
Besitzt einen langlebigen Status | Der ViewModel ist auf den Navigationsgraphen beschränkt. Wenn das Ziel des Autors also nicht aus dem Navigationsgraphen entfernt wird, bleibt der UI-Zustand im uiState StateFlow im Arbeitsspeicher. Die Verwendung von StateFlow bietet außerdem den Vorteil, dass die Anwendung der Geschäftslogik, die den Status erzeugt, verzögert wird, da der Status nur erzeugt wird, wenn ein Collector für den UI-Status vorhanden ist. |
Sie ist für die Benutzeroberfläche eindeutig. | Die AuthorViewModel gilt nur für das Navigationsziel des Autors und kann nicht an anderer Stelle wiederverwendet werden. Wenn Geschäftslogik über Navigationsziele hinweg wiederverwendet wird, muss sie in einer Komponente mit Daten- oder Domänenebenenbereich gekapselt werden. |
ViewModel als Status-Holder für die Geschäftslogik
Die Vorteile von ViewModels in der Android-Entwicklung machen sie geeignet, um Zugriff auf die Geschäftslogik zu ermöglichen und die Anwendungsdaten für die Darstellung auf dem Bildschirm vorzubereiten. Zu diesen Vorteilen gehört Folgendes:
- Von ViewModels ausgelöste Vorgänge überstehen Konfigurationsänderungen.
- Integration mit Navigation:
- Bei der Navigation werden ViewModels im Cache gespeichert, während sich der Bildschirm im Backstack befindet. Das ist wichtig, damit Ihre zuvor geladenen Daten sofort verfügbar sind, wenn Sie an Ihr Ziel zurückkehren. Das ist mit einem Status-Holder, der dem Lebenszyklus des zusammensetzbaren Bildschirms folgt, schwieriger.
- Das ViewModel wird auch gelöscht, wenn das Ziel aus dem Backstack entfernt wird. So wird der Status automatisch bereinigt. Das ist anders als beim Abwarten der Entsorgung des Composables, die aus verschiedenen Gründen erfolgen kann, z. B. beim Wechsel zu einem neuen Bildschirm, aufgrund einer Konfigurationsänderung oder aus anderen Gründen.
- Einbindung in andere Jetpack-Bibliotheken wie Hilt.
UI-Logik und ihr State Holder
Die UI-Logik bezieht sich auf Daten, die von der Benutzeroberfläche selbst bereitgestellt werden. Dies kann sich auf den Status von UI-Elementen oder auf UI-Datenquellen wie die Permissions API oder Resources
beziehen. State Holder, die UI-Logik verwenden, haben in der Regel die folgenden Eigenschaften:
- Erstellt den UI-Zustand und verwaltet den Zustand von UI-Elementen.
- Wird beim erneuten Erstellen nicht beibehalten
Activity
: Statusinhaber, die in der UI-Logik gehostet werden, sind oft von Datenquellen aus der UI selbst abhängig. Wenn Sie versuchen, diese Informationen bei Konfigurationsänderungen beizubehalten, führt das in den meisten Fällen zu einem Speicherleck. Wenn Statusinhaber Daten über Konfigurationsänderungen hinweg beibehalten müssen, müssen sie an eine andere Komponente delegieren, die besser für das Überleben vonActivity
-Neuerstellungen geeignet ist. In Jetpack Compose werden beispielsweise mitremembered
-Funktionen erstellte Status von zusammensetzbaren UI-Elementen häufig anrememberSaveable
delegiert, um den Status bei der Neuerstellung vonActivity
beizubehalten. Beispiele für solche Funktionen sindrememberScaffoldState()
undrememberLazyListState()
. - Verweise auf Datenquellen mit UI-Bereich: Auf Datenquellen wie Lifecycle-APIs und Ressourcen kann sicher verwiesen und aus ihnen gelesen werden, da der UI-Logikstatus-Holder denselben Lebenszyklus wie die Benutzeroberfläche hat.
- Wiederverwendbar in mehreren UIs: Verschiedene Instanzen desselben UI-Logik-Status-Holders können in verschiedenen Teilen der App wiederverwendet werden. Ein Status-Holder zum Verwalten von Nutzereingabeereignissen für eine Chip-Gruppe kann beispielsweise auf einer Suchseite für Filter-Chips und auch für das Feld „An“ für Empfänger einer E-Mail verwendet werden.
Der Status-Holder für die UI-Logik wird in der Regel mit einer einfachen Klasse implementiert. Das liegt daran, dass die UI selbst für die Erstellung des UI-Logik-Status-Holders verantwortlich ist und der UI-Logik-Status-Holder denselben Lebenszyklus wie die UI selbst hat. In Jetpack Compose ist der State Holder beispielsweise Teil der Komposition und folgt dem Lebenszyklus der Komposition.
Das lässt sich anhand des folgenden Beispiels in der Now in Android-Beispiel-App veranschaulichen:

Im Beispiel „Now in Android“ wird je nach Bildschirmgröße des Geräts entweder eine untere App-Leiste oder ein Navigationsstreifen für die Navigation verwendet. Auf kleineren Bildschirmen wird die untere App-Leiste verwendet, auf größeren Bildschirmen die Navigationsleiste.
Da die Logik für die Entscheidung über das geeignete Navigations-UI-Element, das in der zusammensetzbaren Funktion NiaApp
verwendet wird, nicht von der Geschäftslogik abhängt, kann sie von einem einfachen Klassenstatus-Holder namens NiaAppState
verwaltet werden:
@Stable
class NiaAppState(
val navController: NavHostController,
val windowSizeClass: WindowSizeClass
) {
// UI logic
val shouldShowBottomBar: Boolean
get() = windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact ||
windowSizeClass.heightSizeClass == WindowHeightSizeClass.Compact
// UI logic
val shouldShowNavRail: Boolean
get() = !shouldShowBottomBar
// UI State
val currentDestination: NavDestination?
@Composable get() = navController
.currentBackStackEntryAsState().value?.destination
// UI logic
fun navigate(destination: NiaNavigationDestination, route: String? = null) { /* ... */ }
/* ... */
}
Im vorherigen Beispiel sind die folgenden Details zu NiaAppState
bemerkenswert:
- Wird beim erneuten Erstellen von
Activity
nicht beibehalten:NiaAppState
istremembered
in der Komposition, da es mit einer zusammensetzbaren FunktionrememberNiaAppState
erstellt wird, die den Compose-Namenskonventionen entspricht. NachdemActivity
neu erstellt wurde, geht die vorherige Instanz verloren und es wird eine neue Instanz mit allen übergebenen Abhängigkeiten erstellt, die für die neue Konfiguration des neu erstelltenActivity
geeignet ist. Diese Abhängigkeiten können neu sein oder aus der vorherigen Konfiguration wiederhergestellt werden. Beispiel:rememberNavController()
wird im KonstruktorNiaAppState
verwendet und delegiert anrememberSaveable
, um den Status bei der Neuerstellung vonActivity
beizubehalten. - Verweise auf Datenquellen mit UI-Bereich: Verweise auf
navigationController
,Resources
und andere ähnliche Typen mit Lebenszyklusbereich können sicher inNiaAppState
gespeichert werden, da sie denselben Lebenszyklusbereich haben.
Zwischen ViewModel und einfacher Klasse für einen State Holder wählen
Wie in den vorherigen Abschnitten beschrieben, hängt die Entscheidung zwischen einem ViewModel
und einem einfachen Klassenstatus-Holder von der Logik ab, die auf den UI-Status angewendet wird, und von den Datenquellen, auf die sich die Logik bezieht.
Das folgende Diagramm zeigt die Position von State-Holdern in der Pipeline für die UI-Statusgenerierung:

Letztendlich sollten Sie den UI-Zustand mit State-Holdern erzeugen, die sich am nächsten an der Stelle befinden, an der er verwendet wird. Weniger formell ausgedrückt: Sie sollten den Status so niedrig wie möglich halten und gleichzeitig die richtigen Eigentumsrechte beibehalten. Wenn Sie Zugriff auf die Geschäftslogik benötigen und der UI-Status so lange beibehalten werden muss, wie ein Bildschirm aufgerufen werden kann, auch nach dem erneuten Erstellen von Activity
, ist ein ViewModel
eine gute Wahl für die Implementierung des Status-Holders für die Geschäftslogik. Für kurzlebigen UI-Zustand und UI-Logik sollte eine einfache Klasse ausreichen, deren Lebenszyklus ausschließlich von der UI abhängt.
State Holder sind kombinierbar
Statusinhaber können von anderen Statusinhabern abhängen, solange die Abhängigkeiten eine gleiche oder kürzere Lebensdauer haben. Beispiele:
- Ein UI-Logik-State Holder kann von einem anderen UI-Logik-State Holder abhängen.
- Ein Status-Holder auf Bildschirmebene kann von einem Status-Holder für die UI-Logik abhängen.
Das folgende Code-Snippet zeigt, wie Compose-DrawerState
SwipeableState
von einem anderen internen Status-Holder, SwipeableState
, abhängt und wie der Status-Holder der UI-Logik einer App von DrawerState
abhängen kann:
@Stable
class DrawerState(/* ... */) {
internal val swipeableState = SwipeableState(/* ... */)
// ...
}
@Stable
class MyAppState(
private val drawerState: DrawerState,
private val navController: NavHostController
) { /* ... */ }
@Composable
fun rememberMyAppState(
drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed),
navController: NavHostController = rememberNavController()
): MyAppState = remember(drawerState, navController) {
MyAppState(drawerState, navController)
}
Ein Beispiel für eine Abhängigkeit, die länger als ein State Holder besteht, ist ein State Holder für die UI-Logik, der von einem State Holder auf Bildschirmebene abhängt. Dadurch würde die Wiederverwendbarkeit des kurzlebigeren State Holders verringert und er hätte Zugriff auf mehr Logik und Status als tatsächlich erforderlich.
Wenn der kurzlebige State Holder bestimmte Informationen von einem State Holder mit höherem Bereich benötigt, übergeben Sie nur die benötigten Informationen als Parameter, anstatt die State Holder-Instanz zu übergeben. Im folgenden Code-Snippet erhält die Klasse für den Status-Holder der UI-Logik beispielsweise nur die Parameter, die sie vom ViewModel benötigt, anstatt die gesamte ViewModel-Instanz als Abhängigkeit zu übergeben.
class MyScreenViewModel(/* ... */) {
val uiState: StateFlow<MyScreenUiState> = /* ... */
fun doSomething() { /* ... */ }
fun doAnotherThing() { /* ... */ }
// ...
}
@Stable
class MyScreenState(
// DO NOT pass a ViewModel instance to a plain state holder class
// private val viewModel: MyScreenViewModel,
// Instead, pass only what it needs as a dependency
private val someState: StateFlow<SomeState>,
private val doSomething: () -> Unit,
// Other UI-scoped types
private val scaffoldState: ScaffoldState
) {
/* ... */
}
@Composable
fun rememberMyScreenState(
someState: StateFlow<SomeState>,
doSomething: () -> Unit,
scaffoldState: ScaffoldState = rememberScaffoldState()
): MyScreenState = remember(someState, doSomething, scaffoldState) {
MyScreenState(someState, doSomething, scaffoldState)
}
@Composable
fun MyScreen(
modifier: Modifier = Modifier,
viewModel: MyScreenViewModel = viewModel(),
state: MyScreenState = rememberMyScreenState(
someState = viewModel.uiState.map { it.toSomeState() },
doSomething = viewModel::doSomething
),
// ...
) {
/* ... */
}
Das folgende Diagramm zeigt die Abhängigkeiten zwischen der Benutzeroberfläche und den verschiedenen Statusinhabern des vorherigen Code-Snippets:

Produktproben
Die folgenden Google-Beispiele veranschaulichen die Verwendung von Status-Holdern in der UI-Schicht. Sehen Sie sich die folgenden Beispiele an, um zu sehen, wie diese Richtlinien in der Praxis umgesetzt werden:
Empfehlungen für dich
- Hinweis: Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- UI-Ebene
- Zustandsproduktion in der Benutzeroberfläche
- Leitfaden zur App-Architektur