Statusinhaber und UI-Status

Im UI-Ebenen-Leitfaden wird der unidirektionale Datenfluss (UDF) zur Unterstützung Erstellen und Verwalten des UI-Status für die UI-Ebene

<ph type="x-smartling-placeholder">
</ph> Die Daten fließen unidirektional von der Datenschicht zur Benutzeroberfläche.
Abbildung 1: Unidirektionaler Datenfluss

Außerdem werden die Vorteile der Delegation der UDF-Verwaltung an eine spezielle Klasse hervorgehoben. als Staatsinhaber genannt. Sie können einen Inhaber eines Bundesstaates entweder über eine ViewModel oder eine einfache Klasse. In diesem Dokument wird der Zustand genauer beschrieben. die Inhaber und ihre Rolle auf der UI-Ebene.

Am Ende dieses Dokuments sollten Sie wissen, wie Sie Anwendungsstatus auf der UI-Ebene. also die Produktionspipeline für den UI-Status. Ich sollte Folgendes verstehen und wissen können:

  • Informieren Sie sich über die Arten von UI-Status, die auf der UI-Ebene vorhanden sind.
  • Informieren Sie sich über die Arten von Logik, die auf diese UI-Zustände auf der UI-Ebene angewendet werden.
  • Sie müssen wissen, wie Sie die geeignete Implementierung eines Bundesstaatsinhabers, z. B. eines ViewModel oder eine einfache Klasse.

Elemente der Produktionspipeline für den UI-Status

Der UI-Status und die Logik, die ihn erzeugt, definieren die UI-Ebene.

UI-Status

Der UI-Status ist die Eigenschaft, die die UI beschreibt. Es gibt zwei Arten von UI-Elementen. Bundesland:

  • Der Bildschirm-UI-Status gibt an, was auf dem Bildschirm angezeigt werden muss. Beispiel: NewsUiState-Kurs kann die Nachrichtenartikel und andere benötigte Informationen enthalten. um die UI zu rendern. Dieser Zustand ist normalerweise mit anderen Schichten des da sie App-Daten enthält.
  • Der UI-Elementstatus bezieht sich auf Eigenschaften, die UI-Elementen inhärent sind und die wie sie gerendert werden. Ein UI-Element kann ein- oder ausgeblendet sein und eine bestimmte Schriftart, Schriftgröße oder -farbe haben. In Android Views kann die Ansicht verwaltet diesen Zustand selbst, da er inhärent zustandsorientiert ist und Methoden offenlegt, ändern oder abfragen können. Ein Beispiel hierfür sind get und set-Methoden der Klasse TextView für den Text. Im Jetpack Compose-Objekt erstellen, liegt der Status außerhalb der zusammensetzbaren Funktion und Sie können sie sogar winden. aus der unmittelbaren Nähe der zusammensetzbaren Funktion in die aufrufende für eine Funktion oder einen Staatsinhaber sein. Ein Beispiel hierfür ist ScaffoldState für den Scaffold zusammensetzbar.

Logik

Der UI-Status ist keine statische Eigenschaft, da Anwendungsdaten und Nutzerereignisse dazu führen, dass die Benutzeroberfläche die sich im Laufe der Zeit ändern. Die Logik bestimmt die Einzelheiten der Änderung, z. B. welche Teile des UI-Status sich geändert haben, warum und wann geändert werden sollte.

<ph type="x-smartling-placeholder">
</ph> Logik erzeugt UI-Status
Abbildung 2: Logik als Ersteller des UI-Status

Die Logik in einer Anwendung kann entweder Geschäftslogik oder UI-Logik sein:

  • Die Geschäftslogik ist die Implementierung von Produktanforderungen für Apps. Daten. Sie können beispielsweise einen Artikel in einer Newsreader-App als Lesezeichen speichern, tippt auf die Schaltfläche. Diese Logik zum Speichern eines Lesezeichens in einer Datei oder Datenbank normalerweise in den Domänen- oder Datenebenen platziert. Der staatliche Inhaber ist in der Regel delegiert diese Logik an diese Layer, indem die von ihnen bereitgestellten Methoden aufgerufen werden.
  • UI-Logik bezieht sich darauf, wie der UI-Status auf dem Bildschirm angezeigt wird. Für Beispiel: Der richtige Suchleistenhinweis wird angezeigt, wenn der Nutzer eine Kategorie, das Scrollen zu einem bestimmten Element in einer Liste oder die Navigationslogik wenn Nutzende auf eine Schaltfläche klicken.

Android-Lebenszyklus und die Arten von UI-Status und -Logik

Die UI-Ebene besteht aus zwei Teilen: einem abhängigen und einem unabhängigen Teil der UI. Lebenszyklus. Durch diese Trennung wird festgelegt, welche Datenquellen für die einzelnen Teile und erfordert daher verschiedene Arten von UI-Zustand und -Logik.

  • UI-Lebenszyklus unabhängig: Dieser Teil der UI-Ebene befasst sich mit den Daten zur Erstellung von App-Ebenen (Daten- oder Domainebenen) und wird vom Logik. Lebenszyklus, Konfigurationsänderungen und Neuerstellung von Activity in der UI kann sich darauf auswirken, ob die Produktionspipeline für den UI-Status aktiv ist, hat aber keine Auswirkungen die Gültigkeit der erzeugten Daten.
  • Vom UI-Lebenszyklus abhängig: Dieser Teil der UI-Ebene befasst sich mit der UI-Logik und direkt von Lebenszyklus- oder Konfigurationsänderungen beeinflusst. Diese Änderungen sich direkt auf die Gültigkeit der darin gelesenen Datenquellen auswirken. Ergebnis, sein Status kann sich nur ändern, wenn sein Lebenszyklus aktiv ist. Beispiele für Dazu gehören Laufzeitberechtigungen und das Abrufen konfigurationsabhängiger Ressourcen z. B. lokalisierte Zeichenfolgen.

Das kann mit der folgenden Tabelle zusammengefasst werden:

Unabhängig vom UI-Lebenszyklus Vom UI-Lebenszyklus abhängig
Geschäftslogik UI-Logik
Status der Benutzeroberfläche des Bildschirms

Produktionspipeline für den UI-Status

Die Produktionspipeline für den UI-Status bezieht sich auf die Schritte, die zum Erstellen der UI ausgeführt werden. Bundesstaat. Diese Schritte umfassen die Anwendung der definierten Arten von Logik und hängen ganz von den Anforderungen Ihrer Benutzeroberfläche ab. Einige Benutzeroberflächen profitieren sowohl vom UI-Lebenszyklus als auch vom UI-Lebenszyklus der Pipeline entweder oder keinem von beiden entsprechen.

Das heißt, die folgenden Permutationen der UI-Ebenen-Pipeline sind gültig:

  • Der UI-Status, der von der UI selbst erstellt und verwaltet wird. Eine einfache, wiederverwendbarer Basic-Zähler:

    @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. Zum Beispiel das Ein- oder Ausblenden einer Schaltfläche, mit der Nutzende an den Anfang einer Liste springen.

    @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 der Bildschirm.

    @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 Informationen auf dem Bildschirm für einen jeweiligen UI-Zustand richtig angezeigt.

    @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 Erstellung des UI-Zustands angewendet werden Pipeline muss die Geschäftslogik immer vor der UI-Logik angewendet werden. Wird angewendet Nach der UI-Logik würde die Geschäftslogik implizieren, dass die Geschäftslogik von der Benutzeroberfläche abhängt. Logik. In den folgenden Abschnitten wird ausführlich erläutert, verschiedene Logiktypen und ihre Zustandsinhaber.

<ph type="x-smartling-placeholder">
</ph> Daten fließen von der Datenebene zur Benutzeroberfläche.
Abbildung 3: Anwendung der Logik auf der UI-Ebene

Inhaber von Bundesstaaten und ihre Verantwortlichkeiten

Die Verantwortung eines Zustandsinhabers besteht darin, den Status zu speichern, damit die App ihn lesen kann. Wenn Logik erforderlich ist, fungiert sie als Vermittler und bietet Zugriff zu den Datenquellen, die die erforderliche Logik hosten. Auf diese Weise die Logik an die entsprechende Datenquelle delegiert.

Dies hat folgende Vorteile:

  • Einfache Benutzeroberflächen: Die Benutzeroberfläche bindet nur ihren Status.
  • Verwaltbarkeit: Die im Statusinhaber definierte Logik kann iteriert werden. ohne die Benutzeroberfläche selbst zu ändern.
  • Testbarkeit: Die Benutzeroberfläche und ihre Statusproduktionslogik können getestet werden. unabhängig voneinander unterscheiden.
  • Lesbarkeit: Die Leser des Codes können die Unterschiede zwischen der Benutzeroberfläche deutlich erkennen. Präsentationscode und UI-Status-Produktionscode.

Unabhängig von Größe oder Umfang hat jedes UI-Element eine 1:1-Beziehung für den jeweiligen Staatsinhaber. Darüber hinaus müssen Staatsinhaber in der Lage sein, alle Nutzeraktionen zu akzeptieren und zu verarbeiten, die zu einer Änderung des UI-Status führen könnten, die damit einhergehende Statusänderung erzeugen muss.

Arten von Staatsinhabern

Ähnlich wie bei UI-Status und -Logik gibt es zwei Arten von Statusinhabern in der UI-Ebene definiert durch ihre Beziehung zum UI-Lebenszyklus:

  • Der Inhaber der Geschäftslogik.
  • Der Inhaber des UI-Logikstatus.

In den folgenden Abschnitten geht es um die verschiedenen angefangen mit dem Inhaber der Geschäftslogik.

Geschäftslogik und ihr Statusinhaber

Inhaber von Geschäftslogikstatus verarbeiten Nutzerereignisse und transformieren Daten aus den Daten oder der Domain Bildschirm-UI-Status hinzugefügt. Um eine optimale Nutzererfahrung zu bieten, unter Berücksichtigung des Android-Lebenszyklus und der Änderungen an der App-Konfiguration, die Geschäftslogik verwenden, sollten folgende Attribute haben:

Attribut Details
Erzeugt UI-Status Inhaber der Geschäftslogik sind für die Erstellung des UI-Status für ihre UIs verantwortlich. Dieser UI-Status ist häufig das Ergebnis der Verarbeitung von Nutzerereignissen und dem Lesen von Daten aus der Domain und den Datenschichten.
Erhalten durch Freizeitaktivitäten Inhaber von Geschäftslogikstatus behalten ihre Status- und Statusverarbeitungspipelines über die Activity-Neuerstellung hinweg bei und bieten so eine nahtlose Nutzererfahrung. In Fällen, in denen der Zustandsinhaber nicht beibehalten werden kann und neu erstellt wird (normalerweise nach dem Prozess Tod), muss der Inhaber seinen letzten Status einfach reproduzieren können, um eine konsistente Nutzererfahrung zu gewährleisten.
Hat einen langlebigen Zustand Inhaber von Geschäftslogikstatus werden häufig verwendet, um den Status für Navigationsziele zu verwalten. Daher behalten sie häufig ihren Status über alle Navigationsänderungen hinweg bei, bis sie aus dem Navigationsdiagramm entfernt werden.
Sie ist für die zugehörige Benutzeroberfläche eindeutig und nicht wiederverwendbar. Inhaber von Geschäftslogikstatus generieren in der Regel einen Status für eine bestimmte App-Funktion, z. B. eine TaskEditViewModel oder eine TaskListViewModel. Daher gilt sie immer nur für diese App-Funktion. Derselbe Bundesstaat kann diese App-Funktionen für verschiedene Formfaktoren unterstützen. Beispielsweise kann in Smartphone-, TV- und Tablet-Versionen der App derselbe Inhaber der Geschäftslogik verwendet werden.

Nehmen wir zum Beispiel das Navigationsziel des Autors im Feld "Now in Android“ App:

<ph type="x-smartling-placeholder">
</ph> Die App „Now für Android“ zeigt, wie ein Navigationsziel, das eine wichtige App-Funktion darstellt,
in der Geschäftslogik.
Abbildung 4: Die App „Now in Android“

Als Inhaber der Geschäftslogik fungiert der AuthorViewModel erzeugt 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 AuthorViewModel die zuvor beschriebenen Attribute hat:

Attribut Details
produziert AuthorScreenUiState AuthorViewModel liest Daten aus AuthorsRepository und NewsRepository und verwendet diese Daten, um AuthorScreenUiState zu erstellen. Außerdem wird Geschäftslogik angewendet, wenn der Nutzer Author durch Delegieren an die AuthorsRepository folgen oder nicht mehr folgen möchte.
Hat Zugriff auf die Datenschicht Eine Instanz von AuthorsRepository und NewsRepository wird in ihrem Konstruktor an die Instanz übergeben, damit sie die Geschäftslogik für das folgende Ereignis implementieren kann: Author.
Überlebt Activity Freizeit Da er mit einem ViewModel implementiert ist, wird er über eine schnelle Activity-Neuerstellung hinweg beibehalten. Wenn ein Prozess abgebrochen wird, kann das Objekt SavedStateHandle ausgelesen werden, um die Mindestmenge an Informationen bereitzustellen, die zum Wiederherstellen des UI-Status aus der Datenschicht erforderlich sind.
Besitzt langlebigen Zustand ViewModel bezieht sich auf das Navigationsdiagramm. Solange das Ziel des Autors nicht aus dem Navigationsdiagramm entfernt wird, bleibt der Status der Benutzeroberfläche im uiState-StateFlow im Arbeitsspeicher. Die Verwendung von StateFlow bietet außerdem den Vorteil, dass die Anwendung der Geschäftslogik, die den Zustand erzeugt, faul ist, da der Zustand nur erzeugt wird, wenn es einen Collector des UI-Status gibt.
Sie ist einzigartig für die zugehörige Benutzeroberfläche. Das AuthorViewModel gilt nur für das Navigationsziel des Verfassers und kann nirgendwo sonst wiederverwendet werden. Wenn eine Geschäftslogik vorhanden ist, die über Navigationsziele hinweg wiederverwendet wird, muss diese Geschäftslogik in eine Komponente auf Daten- oder Domainebene gekapselt werden.

ViewModel als Inhaber der Geschäftslogik

Dank der Vorteile von ViewModels bei der Android-Entwicklung sind sie für der Zugriff auf die Geschäftslogik ermöglicht und die Anwendungsdaten für auf dem Bildschirm anzuzeigen. Zu diesen Vorteilen gehört Folgendes:

  • Von ViewModels ausgelöste Vorgänge bleiben über Konfigurationsänderungen erhalten.
  • Integration in Navigation: <ph type="x-smartling-placeholder">
      </ph>
    • Navigation speichert ViewModels im Cache, während sich der Bildschirm im Back Stack befindet. Dies ist dass Ihre zuvor geladenen Daten sofort verfügbar sind, wenn Sie zu Ihrem Ziel zurückkehren. Das ist schwieriger, der dem Lebenszyklus des zusammensetzbaren Bildschirms folgt.
    • ViewModel wird auch gelöscht, wenn das Ziel von der Rückseite getrennt wird. Dadurch wird sichergestellt, dass der Zustand automatisch bereinigt wird. Dies ist als auf die zusammensetzbare Entsorgung von Daten, z. B. dass ein neuer Bildschirm aufgerufen wird, weil eine Konfiguration Änderung oder aus anderen Gründen.
  • Integration in andere Jetpack-Bibliotheken wie Hilt

UI-Logik und ihr Statusinhaber

Die UI-Logik ist die Logik, die auf Daten angewendet wird, die von der Benutzeroberfläche selbst bereitgestellt werden. Dabei kann es sich um zu UI-Elementen“ oder auf UI-Datenquellen wie der Permissions API oder Resources State Owners, die Benutzeroberflächenlogik verwenden, haben in der Regel folgenden Properties:

  • Erstellt den UI-Status und verwaltet den Status der UI-Elemente
  • Überlebt nicht die Wiederherstellung von Activity: Staatsinhaber, die in der UI gehostet werden Logik hängt oft von Datenquellen aus der Benutzeroberfläche selbst ab. Beibehalten dieser Informationen bei Konfigurationsänderungen häufiger als nicht zu einem eines Speicherlecks. Wenn die Inhaber der Bundesstaaten Daten über die gesamte Konfiguration hinweg beibehalten müssen ändert sich an eine andere Komponente delegieren müssen, die besser zum Überleben von Activity geeignet ist Freizeitaktivitäten. In Jetpack Compose zum Beispiel „Zusammensetzbare UI-Elementzustände“ Funktionen, die mit remembered-Funktionen erstellt wurden, werden oft an rememberSaveable delegiert, Beibehaltung des Zustands durch die Neuerstellung von Activity. Beispiele für solche Funktionen umfassen rememberScaffoldState() und rememberLazyListState().
  • Enthält Verweise auf UI-bezogene Datenquellen: Datenquellen wie Lebenszyklus-APIs und -Ressourcen können sicher als UI-Logik referenziert und gelesen werden. hat den gleichen Lebenszyklus wie die UI.
  • Ist in mehreren UIs wiederverwendbar: Verschiedene Instanzen derselben UI-Logik kann in verschiedenen Teilen der App wiederverwendet werden. Beispiel: Ein Bundesland Der Inhaber zum Verwalten von Nutzereingabeereignissen für eine Chipgruppe kann bei einer Suche verwendet werden für Infofelder für Filter und für die für Empfänger einer E-Mail.

Der UI-Logikstatusinhaber wird in der Regel mit einer einfachen Klasse implementiert. Dies ist da die UI selbst für die Erstellung des UI-Logikstatus verantwortlich ist. Holder und der UI-Logikstatusinhaber haben denselben Lebenszyklus wie die UI selbst. In Jetpack Compose ist der Staatsinhaber beispielsweise Teil der Komposition und Lebenszyklus der Komposition.

Dies lässt sich anhand des folgenden Beispiels in der Now in Android-Beispiel:

<ph type="x-smartling-placeholder">
</ph> In Android wird jetzt ein einfacher Klassenstatus-Halter verwendet, um die UI-Logik zu verwalten.
Abbildung 5: Das Beispiel „Now in Android“ App

Das Beispiel „Now in Android“ zeigt entweder eine untere App-Leiste oder eine Navigationsleiste für je nach Bildschirmgröße des Geräts anpassen. Für kleinere Bildschirme App-Leiste am unteren Rand und größere Bildschirme die Navigationsleiste.

Da die Logik zur Auswahl des geeigneten UI-Elements für die Navigation in der Die zusammensetzbare Funktion NiaApp hängt nicht von der Geschäftslogik ab und kann verwaltet werden durch einen einfachen Klassenstatusinhaber namens NiaAppState:

@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 obigen Beispiel lauten die folgenden Details zur NiaAppState: beachten:

  • Überlebt Activity-Regeneration nicht: NiaAppState ist remembered in die Komposition mithilfe einer zusammensetzbaren Funktion rememberNiaAppState und folgen Sie dabei den Namenskonventionen für "Compose". Nachdem der Activity neu erstellt wurde, wird der die vorherige Instanz verloren geht und eine neue Instanz mit all ihren übergeben werden, die der neuen Konfiguration des hat Activity neu erstellt. Diese Abhängigkeiten können neu sein oder aus dem vorherigen Konfiguration. rememberNavController() wird beispielsweise verwendet in NiaAppState und delegiert sie an rememberSaveable, den Zustand bei Activity Neuerstellung beibehalten.
  • Enthält Verweise auf UI-bezogene Datenquellen: Verweise auf die navigationController, Resources und andere ähnliche Lebenszyklustypen können sicher in NiaAppState aufbewahrt werden, da sie denselben Lebenszyklusbereich haben.

Wählen Sie zwischen einem ViewModel und einer einfachen Klasse für einen Staatsinhaber aus.

Wählen Sie in den obigen Abschnitten zwischen einem ViewModel- und einem einfachen Klassenstatus auf die Logik angewendet, die auf den UI-Status und die Datenquellen angewendet wird, auf die die Logik arbeitet.

Das Diagramm unten zeigt zusammenfassend die Position von Statusinhabern in der Benutzeroberfläche. Status der Produktionspipeline:

<ph type="x-smartling-placeholder">
</ph> Daten fließen von der Datenerzeugungsschicht zur UI-Ebene.
Abbildung 6: Statusinhaber in der Produktionspipeline für den UI-Status. Pfeile bedeuten Datenfluss.

Letztendlich sollten Sie den UI-Status mit den State Owners erstellen, die am nächsten wo sie konsumiert werden. Weniger formell: Sie sollten so wenig unter Aufrechterhaltung der richtigen Eigentümerschaft möglich. Wenn Sie Zugriff auf geschäftliche und der UI-Status beibehalten werden muss, solange ein Bildschirm aufgerufen wird. Auch in der Kategorie "Activity" ist ein ViewModel eine gute Wahl für die Implementierung des Statusinhabers in der Geschäftslogik. Für kurzlebigen UI-Status und UI-Logik: Eine einfache Klasse, deren Lebenszyklus ausschließlich von der Benutzeroberfläche abhängt, sollte ausreichend ist.

Staatsinhaber können mehrere

Staatsinhaber können sich auf andere Staatsinhaber verlassen, solange die Abhängigkeiten gleicher oder kürzerer Lebensdauer. Beispiele:

  • Ein Inhaber eines UI-Logikstatus kann von einem anderen Inhaber der Benutzeroberflächenlogik abhängig sein.
  • kann ein Statusinhaber auf Bildschirmebene von einem UI-Logikstatusinhaber abhängig sein.

Das folgende Code-Snippet zeigt, wie bei Compose's DrawerState einen anderen internen Statusinhaber, SwipeableState, und wie die UI-Logik Inhaber eines Bundesstaats könnte von DrawerState abhängig sein:

@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 einen Zustandsinhaber überlebt, wäre eine UI-Logik. Dies hängt von einem State Holder auf Bildschirmebene ab. Das würde die Wiederverwendbarkeit des kurzlebigen Staatsinhabers und bietet ihm Zugriff auf mehr Logik. als sie tatsächlich benötigt.

Wenn der Inhaber mit kürzerer Lebensdauer bestimmte Informationen von einem übergeordneten geben Sie als Parameter nur die notwendigen Informationen weiter, und übergeben die Instanz des Statusinhabers. Nehmen wir als Beispiel das folgende Code-Snippet: Die UI-Logik-Zustandsinhaberklasse erhält nur das, was sie als Parameter benötigt. nicht die gesamte ViewModel-Instanz als Abhängigkeit.

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 UI und verschiedenen die Inhaber des vorherigen Code-Snippets sind:

<ph type="x-smartling-placeholder">
</ph> UI abhängig vom Statusinhaber der UI-Logik und vom Statusinhaber auf Bildschirmebene
Abbildung 7: Benutzeroberfläche abhängig von verschiedenen Statusinhabern. Pfeile bedeuten Abhängigkeiten.

Produktproben

In den folgenden Google-Beispielen wird die Verwendung von Staatsinhabern in der Region UI-Ebene. Sehen Sie sich diese Tipps in der Praxis an: