Je nachdem, wo Ihr Bundesstaat hochgezogen wird und welche Logik erforderlich ist, können Sie verschiedene APIs verwenden, um Ihren UI-Status zu speichern und wiederherzustellen. Dazu wird bei jeder Anwendung eine Kombination aus APIs verwendet.
Android-Apps können ihren UI-Status aufgrund von Aktivitäten oder Prozessen verlieren. Dieser Statusverlust kann durch folgende Ereignisse auftreten:
- Konfigurationsänderungen: Die Aktivität wird gelöscht und neu erstellt, sofern die Konfigurationsänderung nicht manuell verarbeitet wird.
- Vom System initiierter Prozesstod: Die App wird im Hintergrund ausgeführt und das Gerät gibt Ressourcen wie Arbeitsspeicher frei, die von anderen Prozessen verwendet werden können.
Die Beibehaltung des Zustands nach diesen Ereignissen ist für eine positive Nutzererfahrung unerlässlich. Die Auswahl des beibehaltenen Status hängt von den Abläufen einzelner Nutzer in Ihrer Anwendung ab. Es hat sich bewährt, zumindest die Nutzereingabe und den navigationsbezogenen Status beizubehalten. Beispiele dafür sind die Scrollposition einer Liste, die ID des Elements, über das der Nutzer weitere Informationen wünscht, die Auswahl von Nutzereinstellungen in Bearbeitung oder Eingaben in Textfeldern.
Auf dieser Seite werden die APIs zusammengefasst, die zum Speichern des UI-Status verfügbar sind, je nachdem, wo Ihr Bundesstaat hochgezogen wird und welche Logik ihn benötigt.
UI-Logik
Wenn Ihr Zustand in der UI entweder in zusammensetzbaren Funktionen oder in einfachen Status-Holder-Klassen, die auf die Zusammensetzung beschränkt sind, hochgezogen wird, können Sie rememberSaveable
verwenden, um den Status über Aktivitäten und Prozesswiederherstellungen hinweg beizubehalten.
Im folgenden Snippet wird mit rememberSaveable
der Status eines einzelnen booleschen UI-Elements gespeichert:
@Composable fun ChatBubble( message: Message ) { var showDetails by rememberSaveable { mutableStateOf(false) } ClickableText( text = AnnotatedString(message.content), onClick = { showDetails = !showDetails } ) if (showDetails) { Text(message.timestamp) } }
showDetails
ist eine boolesche Variable, die gespeichert wird, ob das Chat-Infofeld minimiert oder maximiert wird.
rememberSaveable
speichert den Status des UI-Elements über den gespeicherten Instanzstatusmechanismus in einem Bundle
.
Es kann primitive Typen automatisch im Bundle speichern. Wenn der Status in einem nicht einfachen Typ enthalten ist, z. B. einer Datenklasse, können Sie verschiedene Speichermechanismen verwenden, z. B. die Annotation Parcelize
, Compose APIs wie listSaver
und mapSaver
oder eine benutzerdefinierte Saver-Klasse implementieren, um die Compose-Laufzeitklasse Saver
zu erweitern. Weitere Informationen zu diesen Methoden finden Sie in der Dokumentation zu Möglichkeiten zum Speichern von Status.
Im folgenden Snippet wird in der rememberLazyListState
Compose API LazyListState
gespeichert. Dieser Wert umfasst den Scrollstatus von LazyColumn
oder LazyRow
mit rememberSaveable
. Dabei wird ein LazyListState.Saver
verwendet. Das ist ein benutzerdefinierter Speicher, mit dem der Scrollstatus gespeichert und wiederhergestellt werden kann. Nach der Neuerstellung einer Aktivität oder eines Prozesses (z. B. nach einer Konfigurationsänderung wie einer Änderung der Geräteausrichtung) wird der Scrollstatus beibehalten.
@Composable fun rememberLazyListState( initialFirstVisibleItemIndex: Int = 0, initialFirstVisibleItemScrollOffset: Int = 0 ): LazyListState { return rememberSaveable(saver = LazyListState.Saver) { LazyListState( initialFirstVisibleItemIndex, initialFirstVisibleItemScrollOffset ) } }
Best Practice
rememberSaveable
verwendet ein Bundle
zum Speichern des UI-Status, der von anderen APIs gemeinsam genutzt wird, die ebenfalls in ihn schreiben, z. B. onSaveInstanceState()
-Aufrufe in Ihrer Aktivität. Die Größe dieses Bundle
ist jedoch begrenzt und das Speichern großer Objekte kann während der Laufzeit zu TransactionTooLarge
-Ausnahmen führen. Dies kann besonders bei einzelnen Activity
-Anwendungen problematisch sein, bei denen in der gesamten App dasselbe Bundle
verwendet wird.
Um diese Art von Absturz zu vermeiden, sollten Sie keine großen komplexen Objekte oder Listen von Objekten im Bundle speichern.
Speichern Sie stattdessen den erforderlichen Mindeststatus wie IDs oder Schlüssel und verwenden Sie diese, um die Wiederherstellung des komplexeren UI-Status an andere Mechanismen wie nichtflüchtigen Speicher zu delegieren.
Diese Designentscheidungen hängen von den spezifischen Anwendungsfällen für Ihre Anwendung und dem Verhalten Ihrer Nutzer ab.
Wiederherstellung des Status prüfen
Sie können prüfen, ob der mit rememberSaveable
in Ihren Composer-Elementen gespeicherte Status korrekt wiederhergestellt wird, wenn die Aktivität oder der Prozess neu erstellt wird. Dafür gibt es bestimmte APIs, z. B. StateRestorationTester
. Weitere Informationen finden Sie in der Testdokumentation.
Geschäftslogik
Wenn Ihr UI-Elementstatus in die ViewModel
gezogen wird, weil dies für die Geschäftslogik erforderlich ist, können Sie die APIs von ViewModel
verwenden.
Einer der Hauptvorteile der Verwendung von ViewModel
in deiner Android-App besteht darin, dass Konfigurationsänderungen kostenlos verarbeitet werden. Wenn es eine Konfigurationsänderung gibt und die Aktivität gelöscht und neu erstellt wird, wird der UI-Status, der in ViewModel
übertragen wurde, im Arbeitsspeicher gehalten. Nach der Neuerstellung wird die alte ViewModel
-Instanz der neuen Aktivitätsinstanz zugeordnet.
Eine ViewModel
-Instanz überlebt den vom System initiierten Prozessende jedoch nicht.
Damit der UI-Status bestehen bleibt, verwenden Sie das Saved State-Modul für ViewModel, das die SavedStateHandle
API enthält.
Best Practice
In SavedStateHandle
wird auch der Bundle
-Mechanismus zum Speichern des UI-Status verwendet. Daher sollten Sie ihn nur zum Speichern eines einfachen UI-Elementstatus verwenden.
Der Bildschirm-UI-Status, der durch die Anwendung von Geschäftsregeln und den Zugriff auf andere Ebenen Ihrer Anwendung als UI generiert wird, sollte aufgrund seiner potenziellen Komplexität und Größe nicht in SavedStateHandle
gespeichert werden. Sie können verschiedene Mechanismen zum Speichern komplexer oder großer Daten verwenden, beispielsweise lokaler nichtflüchtiger Speicher. Nach einer Prozesswiederherstellung wird der Bildschirm mit dem wiederhergestellten vorübergehenden Status neu erstellt, der gegebenenfalls in SavedStateHandle
gespeichert wurde. Der Bildschirm-UI-Status wird wieder aus der Datenschicht erzeugt.
SavedStateHandle
APIs
SavedStateHandle
hat verschiedene APIs zum Speichern des Status der UI-Elemente, insbesondere:
Schreiben State |
saveable() |
---|---|
StateFlow |
getStateFlow() |
State
verfassen
Verwenden Sie die saveable
API von SavedStateHandle
, um den Status des UI-Elements als MutableState
zu lesen und zu schreiben. So werden Aktivitäten und Neuerstellungen mit minimaler Codeeinrichtung überstanden.
Die saveable
API unterstützt standardmäßig primitive Typen und empfängt einen stateSaver
-Parameter, um benutzerdefinierte Saver wie rememberSaveable()
zu verwenden.
Im folgenden Snippet speichert message
die Nutzereingabetypen in einer TextField
:
class ConversationViewModel( savedStateHandle: SavedStateHandle ) : ViewModel() { var message by savedStateHandle.saveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) } private set fun update(newMessage: TextFieldValue) { message = newMessage } /*...*/ } val viewModel = ConversationViewModel(SavedStateHandle()) @Composable fun UserInput(/*...*/) { TextField( value = viewModel.message, onValueChange = { viewModel.update(it) } ) }
Weitere Informationen zur Verwendung der saveable
API finden Sie in der Dokumentation zu SavedStateHandle
.
StateFlow
Verwenden Sie getStateFlow()
, um den Status des UI-Elements zu speichern und als Ablauf aus SavedStateHandle
zu übernehmen. Das StateFlow
ist schreibgeschützt und die API erfordert, dass Sie einen Schlüssel angeben, damit Sie den Ablauf ersetzen können, um einen neuen Wert auszugeben. Mit dem von Ihnen konfigurierten Schlüssel können Sie StateFlow
abrufen und den neuesten Wert erfassen.
Im folgenden Snippet ist savedFilterType
eine StateFlow
-Variable, die einen Filtertyp speichert, der auf eine Liste von Chatkanälen in einer Chat-App angewendet wird:
private const val CHANNEL_FILTER_SAVED_STATE_KEY = "ChannelFilterKey" class ChannelViewModel( channelsRepository: ChannelsRepository, private val savedStateHandle: SavedStateHandle ) : ViewModel() { private val savedFilterType: StateFlow<ChannelsFilterType> = savedStateHandle.getStateFlow( key = CHANNEL_FILTER_SAVED_STATE_KEY, initialValue = ChannelsFilterType.ALL_CHANNELS ) private val filteredChannels: Flow<List<Channel>> = combine(channelsRepository.getAll(), savedFilterType) { channels, type -> filter(channels, type) }.onStart { emit(emptyList()) } fun setFiltering(requestType: ChannelsFilterType) { savedStateHandle[CHANNEL_FILTER_SAVED_STATE_KEY] = requestType } /*...*/ } enum class ChannelsFilterType { ALL_CHANNELS, RECENT_CHANNELS, ARCHIVED_CHANNELS }
Jedes Mal, wenn der Nutzer einen neuen Filtertyp auswählt, wird setFiltering
aufgerufen. Dadurch wird in SavedStateHandle
ein neuer Wert gespeichert, der mit dem Schlüssel _CHANNEL_FILTER_SAVED_STATE_KEY_
gespeichert wird. savedFilterType
ist ein Ablauf, der den neuesten im Schlüssel gespeicherten Wert ausgibt. filteredChannels
hat den Ablauf abonniert, um die Kanalfilterung durchzuführen.
Weitere Informationen zur getStateFlow()
API finden Sie in der Dokumentation zu SavedStateHandle
.
Zusammenfassung
In der folgenden Tabelle erhalten Sie eine Übersicht über die in diesem Abschnitt behandelten APIs und ihre Verwendung zum Speichern des UI-Status:
Veranstaltung | UI-Logik | Geschäftslogik in einer ViewModel |
---|---|---|
Konfigurationsänderungen | rememberSaveable |
Automatisch |
Vom System initiierter Tod | rememberSaveable |
SavedStateHandle |
Welche API verwendet wird, hängt davon ab, wo sich der Status befindet und welche Logik er erfordert. Verwende rememberSaveable
für einen Status, der in der UI-Logik verwendet wird. Wenn Sie einen Status, der in der Geschäftslogik verwendet wird, in einer ViewModel
speichern, speichern Sie ihn mit SavedStateHandle
.
Sie sollten die Bundle APIs (rememberSaveable
und SavedStateHandle
) verwenden, um kleine Mengen an UI-Status zu speichern. Diese Daten sind das Minimum, das erforderlich ist, um den vorherigen Zustand der UI wiederherzustellen, zusammen mit anderen Speichermechanismen. Wenn Sie beispielsweise die ID eines Profils speichern, das sich der Nutzer im Bundle angesehen hat, können Sie umfangreiche Daten wie Profildetails aus der Datenschicht abrufen.
Weitere Informationen zu den verschiedenen Möglichkeiten zum Speichern des UI-Status finden Sie in der allgemeinen Dokumentation zum Speichern des UI-Status und auf der Seite Datenschicht des Architekturleitfadens.
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Wo soll Winde erreicht werden?
- State und Jetpack Compose
- Listen und Raster