ViewModel – Übersicht Teil von Android Jetpack.
Die ViewModel Klasse ist ein State Holder auf Geschäftslogik- oder Bildschirmebene. Sie stellt den Status für die Benutzeroberfläche bereit und kapselt die zugehörige Geschäftslogik.
Der Hauptvorteil besteht darin, dass der Status im Cache gespeichert und bei Konfigurationsänderungen beibehalten wird. Das bedeutet, dass die Benutzeroberfläche beim Wechsel zwischen Aktivitäten oder nach Konfigurationsänderungen, z. B. beim Drehen des Bildschirms, keine Daten noch einmal abrufen muss.
Weitere Informationen zu Status-Holdern finden Sie in der Anleitung zu Status-Holdern. Weitere Informationen zur Benutzeroberfläche finden Sie in der Anleitung zur Benutzeroberfläche.
Vorteile von ViewModel
Die Alternative zu einem ViewModel ist eine einfache Klasse, die die Daten enthält, die Sie auf der Benutzeroberfläche anzeigen. Dies kann beim Wechsel zwischen Aktivitäten oder Navigationszielen zu Problemen führen. Dabei werden die Daten zerstört, wenn Sie sie nicht mit dem Mechanismus für den gespeicherten Instanzstatus speichern. ViewModel bietet eine praktische API für die Datenpersistenz, mit der dieses Problem behoben wird.
Alternativ bietet Compose für reine Status-Holder retain-Funktionen, mit denen einfache Klassen Konfigurationsänderungen überstehen können, ohne die vollständige Infrastruktur eines ViewModels zu benötigen. Beide Mechanismen helfen zwar bei der Statusbeibehaltung, es ist jedoch im Allgemeinen sicherer, einer beibehaltenen Instanz ein ViewModel bereitzustellen als umgekehrt, da sich ihre Lebenszyklen und Bereinigungsverhalten unterscheiden.
Die wichtigsten Vorteile der ViewModel-Klasse sind:
- Sie ermöglicht es Ihnen, den UI-Status beizubehalten.
- Sie bietet Zugriff auf die Geschäftslogik.
Persistenz
ViewModel ermöglicht die Persistenz sowohl durch den Status, den ein ViewModel enthält, als auch durch die Vorgänge, die ein ViewModel auslöst. Durch das Caching müssen Sie Daten bei häufigen Konfigurationsänderungen, z. B. beim Drehen des Bildschirms, nicht noch einmal abrufen.
Umfang
Wenn Sie ein ViewModel instanziieren, übergeben Sie ihm ein Objekt, das die
ViewModelStoreOwner Schnittstelle implementiert. Dabei kann es sich um ein Navigationsziel, einen Navigationsgraphen, eine Aktivität oder einen anderen Typ handeln, der die Schnittstelle implementiert. Sie können ein ViewModel auch direkt auf eine zusammensetzbare Funktion beschränken, indem Sie
die rememberViewModelStoreOwner API verwenden.
Ihr ViewModel ist dann auf den Lebenszyklus des
ViewModelStoreOwner beschränkt. Es bleibt im Arbeitsspeicher, bis der ViewModelStoreOwner endgültig entfernt wird (z. B. wenn der zusammensetzbare Inhaber die Komposition verlässt).
Eine Reihe von Klassen sind direkte oder indirekte Unterklassen der Schnittstelle ViewModelStoreOwner. Die direkten Unterklassen sind
ComponentActivity und NavBackStackEntry.
Eine vollständige Liste der indirekten Unterklassen finden Sie in der
ViewModelStoreOwner Referenz. Wenn Sie ViewModels auf einzelne Elemente in einer LazyList oder einem Pager beschränken möchten, verwenden Sie rememberViewModelStoreProvider(), um die Inhaberverwaltung an das übergeordnete Element zu übertragen.
Wenn sich die Konfiguration der Hostaktivität ändert, werden asynchrone Vorgänge im ViewModel fortgesetzt, unabhängig davon, ob es auf die Aktivität oder auf eine bestimmte zusammensetzbare Funktion beschränkt ist. Das ist der Schlüssel zur Persistenz.
Weitere Informationen finden Sie im folgenden Abschnitt ViewModel-Lebenszyklus, unter ViewModel-Scoping-APIs, und in der Anleitung zum Status-Hoisting für Jetpack Compose.
SavedStateHandle
SavedStateHandle ermöglicht es Ihnen, Daten nicht nur bei Konfigurations änderungen, sondern auch bei Prozessabstürzen beizubehalten. So bleibt der UI-Status auch dann erhalten, wenn der Nutzer die App schließt und später wieder öffnet.
Weitere Informationen zum Speichern des UI-Status finden Sie unter UI-Status in Compose speichern.
Zugriff auf die Geschäftslogik
Obwohl die meisten Geschäftslogik in der Daten schicht vorhanden ist, kann die Benutzeroberfläche auch Geschäftslogik enthalten. Das kann der Fall sein, wenn Daten aus mehreren Repositories kombiniert werden, um den UI-Status des Bildschirms zu erstellen, oder wenn für einen bestimmten Datentyp keine Datenschicht erforderlich ist.
ViewModel ist der richtige Ort, um Geschäftslogik in der Benutzeroberfläche zu verarbeiten. Das ViewModel ist auch für die Verarbeitung von Ereignissen und deren Weiterleitung an andere Ebenen der Hierarchie zuständig, wenn Geschäftslogik angewendet werden muss, um Anwendungsdaten zu ändern.
ViewModel implementieren
Im Folgenden finden Sie eine Beispielimplementierung eines ViewModels für einen Bildschirm, auf dem der Nutzer würfeln kann.
data class DiceUiState(
val firstDieValue: Int? = null,
val secondDieValue: Int? = null,
val numberOfRolls: Int = 0,
)
class DiceRollViewModel : ViewModel() {
// Expose screen UI state
private val _uiState = MutableStateFlow(DiceUiState())
val uiState: StateFlow<DiceUiState> = _uiState.asStateFlow()
// Handle business logic
fun rollDice() {
_uiState.update { currentState ->
currentState.copy(
firstDieValue = Random.nextInt(from = 1, until = 7),
secondDieValue = Random.nextInt(from = 1, until = 7),
numberOfRolls = currentState.numberOfRolls + 1,
)
}
}
}
Sie können dann wie folgt auf das ViewModel von einer zusammensetzbaren Funktion auf Bildschirmebene zugreifen:
import androidx.lifecycle.viewmodel.compose.viewModel
// Use the 'viewModel()' function from the lifecycle-viewmodel-compose artifact
@Composable
fun DiceRollScreen(
viewModel: DiceRollViewModel = viewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
// Update UI elements
}
Coroutinen mit ViewModel verwenden
ViewModel unterstützt Kotlin-Coroutinen. Es kann asynchrone Vorgänge auf dieselbe Weise beibehalten wie den UI-Status.
Weitere Informationen finden Sie unter Kotlin-Coroutinen mit Android-Architektur komponenten verwenden.
Der Lebenszyklus eines ViewModels
Der Lebenszyklus eines ViewModel ist direkt an seinen Umfang gebunden. A ViewModel
bleibt im Arbeitsspeicher, bis der ViewModelStoreOwner, auf den es beschränkt ist,
entfernt wird. Dies kann in den folgenden Kontexten auftreten:
- Bei einer Aktivität, wenn sie beendet wird.
- Bei einem Navigationseintrag, wenn er aus dem Back-Stack entfernt wird.
- Bei einer zusammensetzbaren Funktion, wenn sie die Komposition verlässt.
Mit
rememberViewModelStoreOwnerkönnen Sie ein ViewModel direkt auf einen beliebigen Teil der Benutzeroberfläche beschränken (z. B. einenPageroder eineLazyList).
ViewModels sind daher eine gute Lösung zum Speichern von Daten, die Konfigurationsänderungen überstehen.
Abbildung 1 veranschaulicht die verschiedenen Lebenszyklusstatus einer Aktivität, während sie gedreht und dann beendet wird. Die Abbildung zeigt auch die Lebensdauer des
ViewModel neben dem zugehörigen Aktivitätslebenszyklus. Dieses Diagramm veranschaulicht die Status einer Aktivität.
Normalerweise fordern Sie ein ViewModel an, wenn das System zum ersten Mal die Methode onCreate() eines
Aktivitätsobjekts aufruft. Das System kann
onCreate() während der Lebensdauer einer Activity mehrmals aufrufen, z. B.
wenn der Bildschirm eines Geräts gedreht wird. Das ViewModel ist ab dem Zeitpunkt vorhanden, an dem Sie
es zum ersten Mal anfordern, bis die Aktivität beendet und zerstört wird.ViewModel
ViewModel-Abhängigkeiten löschen
Das ViewModel ruft die onCleared Methode auf, wenn der ViewModelStoreOwner
es im Laufe seines Lebenszyklus zerstört. So können Sie alle Vorgänge oder Abhängigkeiten bereinigen, die dem Lebenszyklus des ViewModels folgen.
Das folgende Beispiel zeigt eine Alternative zu viewModelScope.
viewModelScope ist ein integrierter CoroutineScope, der
automatisch dem Lebenszyklus des ViewModels folgt. Das ViewModel verwendet es, um geschäftsbezogene Vorgänge auszulösen. Wenn Sie anstelle von
viewModelScope einen benutzerdefinierten Umfang verwenden möchten, um Tests zu vereinfachen, kann das ViewModel in seinem Konstruktor einen
CoroutineScope als Abhängigkeit erhalten. Wenn der ViewModelStoreOwner das ViewModel am Ende seines Lebenszyklus löscht, bricht das ViewModel auch den CoroutineScope ab.
class MyViewModel(
private val coroutineScope: CoroutineScope =
CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
) : ViewModel() {
// Other ViewModel logic ...
override fun onCleared() {
coroutineScope.cancel()
}
}
Ab der Lebenszyklusversion 2.5 und höher können Sie dem Konstruktor des ViewModels ein oder mehrere CloseableObjekte übergeben, die automatisch geschlossen werden, wenn die ViewModel-Instanz gelöscht wird.
class CloseableCoroutineScope(
context: CoroutineContext = SupervisorJob() + Dispatchers.Main.immediate
) : Closeable, CoroutineScope {
override val coroutineContext: CoroutineContext = context
override fun close() {
coroutineContext.cancel()
}
}
class MyViewModel(
private val coroutineScope: CoroutineScope = CloseableCoroutineScope()
) : ViewModel(coroutineScope) {
// Other ViewModel logic ...
}
Best Practices
Im Folgenden finden Sie einige wichtige Best Practices, die Sie bei der Implementierung von ViewModel beachten sollten:
- Verwenden Sie ViewModels aufgrund ihres Umfangs als Implementierungsdetails eines Status-Holders auf Bildschirmebene. Verwenden Sie sie nicht als Status-Holder für wiederverwendbare UI-Komponenten wie Chip-Gruppen oder Formulare. Andernfalls erhalten Sie dieselbe ViewModel-Instanz bei verschiedenen Verwendungen derselben UI-Komponente unter demselben ViewModelStoreOwner, es sei denn, Sie verwenden einen expliziten ViewModel-Schlüssel pro Chip.
- ViewModels sollten keine Details zur UI-Implementierung kennen. Halten Sie die Namen der Methoden, die die ViewModel API bereitstellt, und die Namen der UI-Statusfelder so allgemein wie möglich. So kann Ihr ViewModel für jede Art von Benutzeroberfläche verwendet werden: Smartphone, faltbares Gerät, Tablet oder sogar Chromebook.
- Da sie möglicherweise länger als der
ViewModelStoreOwneraktiv sind, sollten ViewModels keine Verweise auf APIs im Zusammenhang mit dem Lebenszyklus wieContextoderResourcesenthalten, um Speicherlecks zu vermeiden. - Übergeben Sie keine ViewModels an andere Klassen, Funktionen oder andere UI-Komponenten. Da sie von der Plattform verwaltet werden, sollten Sie sie so nah wie möglich an der Plattform halten – in der Nähe Ihrer Aktivität, der zusammensetzbaren Funktion auf Bildschirmebene oder des Navigationsziels. So wird verhindert, dass Komponenten auf niedrigerer Ebene auf mehr Daten und Logik zugreifen, als sie benötigen.
Weitere Informationen
Wenn Ihre Daten komplexer werden, können Sie eine separate Klasse nur zum Laden der Daten verwenden. Der Zweck von ViewModel besteht darin, die Daten für
einen UI-Controller zu kapseln, damit die Daten Konfigurationsänderungen überstehen. Informationen
zum Laden, Beibehalten und Verwalten von Daten bei Konfigurationsänderungen finden Sie unter
Gespeicherte UI-Status.
In der Anleitung zur Android-App-Architektur wird empfohlen, eine Repository-Klasse zu erstellen, um diese Funktionen zu verarbeiten.
Zusätzliche Ressourcen
Weitere Informationen zur Klasse ViewModel finden Sie in den folgenden Ressourcen.
Dokumentation
Ansichten
Beispiele
Empfehlungen für Sie
- Hinweis: Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Kotlin-Coroutinen mit lebenszyklusabhängigen Komponenten verwenden
- UI-Status speichern
- Paginierte Daten laden und anzeigen