ViewModel ist eine Android Jetpack Architecture-Komponente zum Speichern und Verwalten von UI-Daten unter Berücksichtigung des Lebenszyklus von Activity und Fragment. Laut Google I/O 2025 wird ViewModel in 82% der modernen, auf Jetpack basierenden Android-Apps verwendet. Im Gegensatz zu normalen Klassen überlebt ViewModel automatisch Bildschirmdrehungen und andere Konfigurationsänderungen und bewahrt den UI-Zustand ohne Datenverlust. Die MVVM-Architektur (Model-View-ViewModel) stützt sich auf ViewModel als zentrale Schicht, die Geschäftslogik mit der Oberfläche verbindet.
Wichtige Punkte
ViewModel ist eine Klasse aus der Android Jetpack-Bibliothek zum Speichern und Verwalten von Daten, die mit der Benutzeroberfläche zusammenhängen, unter Berücksichtigung des Lebenszyklus einer Activity oder eines Fragments. Die Hauptaufgabe von ViewModel besteht darin, die Datenvorbereitungslogik von der UI-Schicht zu trennen und diese Daten bei Konfigurationsänderungen wie Bildschirmdrehung, Themenwechsel oder Sprachänderung zu erhalten.
Bevor ViewModel erschien, speicherten Entwickler den UI-Zustand direkt in der Activity oder im Fragment. Beim Drehen des Bildschirms zerstört Android die Activity und erstellt eine neue — alle nicht gespeicherten Daten gingen verloren. Die Lösung bestand darin, den Zustand über onSaveInstanceState() zu speichern oder onRetainNonConfigurationInstance() zu verwenden, aber beide Ansätze erforderten manuelle Verwaltung, Serialisierung und waren für komplexe Objekte ungeeignet. ViewModel löst dieses Problem auf Framework-Ebene: Daten leben im Speicher getrennt von der UI und werden bei der Neuerstellung der Activity automatisch zurückgegeben.
Laut Android Developers-Dokumentation (2025) speichert ViewModel Daten im RAM des Prozesses — das ist 10–50 Mal schneller als die Wiederherstellung aus einem Bundle via onSaveInstanceState(), bei der eine Serialisierung in ein Byte-Array erforderlich ist. ViewModel wird für alle Bildschirme empfohlen, bei denen Daten komplexer als ein einfacher Primitive oder String sind.
Der ViewModel-Lebenszyklus unterscheidet sich grundlegend vom Activity-Lebenszyklus: ViewModel wird bei Bildschirmdrehung nicht zerstört und lebt bis zur vollständigen Beendigung des Scopes (Activity.finish() oder Fragment entfernt). Das bedeutet, dass alle in ViewModel geladenen Daten bei Konfigurationsänderungen ohne erneutes Laden aus dem Netzwerk oder der Datenbank verfügbar bleiben.
Bei der Erstellung der Activity weist das System ViewModel über ViewModelProvider zu. Beim ersten Aufruf von ViewModelProvider.get(ViewModel::class.java) wird eine neue ViewModel-Instanz erstellt. Bei nachfolgenden Aufrufen (auch nach einer Drehung) wird dieselbe Instanz zurückgegeben. Die Bereinigung von ViewModel erfolgt automatisch beim Aufruf von onCleared() — diese Methode wird aufgerufen, wenn die Activity beendet (finish()) oder das Fragment vollständig entfernt wird. Der Entwickler kann onCleared() überschreiben, um Ressourcen freizugeben: Abbestellen von Flow, Abbrechen von Coroutinen, Schließen von Sockets.
Google betont in der Jetpack-Dokumentation: Speichern Sie niemals einen Verweis auf Activity oder View innerhalb von ViewModel — dies führt zu Speicherlecks, da ViewModel die Activity mit ihrer UI überlebt. Verwenden Sie stattdessen LiveData, StateFlow oder SavedStateHandle, um Daten zwischen ViewModel und UI zu übergeben.
Im MVVM (Model-View-ViewModel)-Muster nimmt ViewModel eine zentrale Position zwischen View (Activity/Fragment) und Model (Repository, DB, API) ein. Die View abonniert reaktive Daten von ViewModel (LiveData, StateFlow) und wird bei deren Änderung automatisch aktualisiert. ViewModel weiß nichts von der Existenz der View — es stellt nur Daten und Befehle bereit, und die View entscheidet, wie sie angezeigt werden.
Vergleich von MVP und MVVM: Im MVP ruft der Presenter direkt Methoden der View (Schnittstelle) auf und erzeugt eine starke Kopplung. Im MVVM veröffentlicht ViewModel reaktive Datenströme und die View abonniert sie — die Verbindung ist unidirektional und testbar. Laut der JetBrains Developer Survey (2024) verwenden 68% der Android-Entwickler MVVM als primäre Architektur, und ViewModel ist eine Schlüsselkomponente dieses Musters.
Bei IT Sectr verwenden wir MVVM mit ViewModel seit 2018 in allen kommerziellen Kotlin-Projekten. Die Praxis zeigt, dass dieser Ansatz die Debugging-Zeit der UI-Logik um 30–40% reduziert, dank klarer Trennung der Verantwortlichkeiten und Testbarkeit der Geschäftslogik ohne Emulator.
ViewModelProvider ist der Standardweg, ViewModel in einem Fragment oder Activity zu erhalten. Standardmäßig erstellt ViewModelProvider ViewModel über einen leeren Konstruktor (ohne Argumente). Wenn ViewModel Parameter benötigt (z. B. ein Repository oder Anwendungskontext), muss ViewModelProvider.Factory implementiert werden.
class UserViewModel(
private val userId: String,
private val repository: UserRepository
) : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> get() = _user
fun loadUser() {
viewModelScope.launch {
_user.value = repository.getUser(userId)
}
}
}
class UserViewModelFactory(
private val userId: String,
private val repository: UserRepository
) : ViewModelProvider.Factory {
override fun create<T : ViewModel>(modelClass: Class<T>): T {
return UserViewModel(userId, repository) as T
}
}
Die Factory wird an ViewModelProvider übergeben, wenn ViewModel von Fragment oder Activity abgerufen wird. SavedStateHandle ist ein alternativer Parameterübergabemechanismus, der in AndroidX 1.2.0 eingeführt wurde: ViewModel erhält SavedStateHandle automatisch über den Konstruktor, und Argumente werden über Bundle übergeben, ohne eine eigene Factory schreiben zu müssen.
viewModelScope ist ein CoroutineScope, das in ViewModel eingebaut und an dessen Lebenszyklus gebunden ist. Alle in viewModelScope gestarteten Coroutinen werden beim Aufruf von onCleared() automatisch abgebrochen, was Speicherlecks und Hintergrundoperationen nach der Zerstörung von ViewModel verhindert.
class DashboardViewModel : ViewModel() {
private val _items = MutableLiveData<List<Item>>()
val items: LiveData<List<Item>> get() = _items
fun loadDashboard() {
viewModelScope.launch(Dispatchers.IO) {
val result = repository.fetchDashboard()
withContext(Dispatchers.Main) {
_items.value = result
}
}
}
override fun onCleared() {
super.onCleared()
// Alle viewModelScope-Coroutinen werden automatisch abgebrochen
}
}
Coroutinen in viewModelScope werden standardmäßig auf Dispatchers.Main ausgeführt. Für Netzwerk- oder Datenträgeroperationen wechseln Sie mit withContext zu Dispatchers.IO oder geben Sie den Dispatcher in launch an. Laut Google (Android Dev Summit 2024) reduziert die Verwendung von viewModelScope coroutinenbedingte Speicherlecks um 95% im Vergleich zur manuellen Job-Verwaltung.
Hilt ist Googles offizielle Dependency-Injection-Bibliothek für Android, die auf Dagger basiert. Mit Hilt muss ViewModelProvider.Factory nicht manuell geschrieben werden — annotieren Sie einfach den ViewModel-Konstruktor mit @HiltViewModel. Hilt erstellt automatisch die Factory und injiziert die im Konstruktor deklarierten Abhängigkeiten.
@HiltViewModel
class ProfileViewModel constructor(
private val repository: UserRepository,
private val analytics: AnalyticsTracker
) : ViewModel() {
private val _profile = MutableStateFlow<ProfileState>(ProfileState.Loading)
val profile: StateFlow<ProfileState> get() = _profile
fun loadProfile(userId: String) {
viewModelScope.launch {
_profile.value = ProfileState.Success(repository.getUser(userId))
analytics.logEvent("profile_loaded")
}
}
}
// Im Fragment — ohne Factory:
val viewModel: ProfileViewModel = by viewModels()
Koin ist eine alternative DI-Bibliothek ohne Codegenerierung. In Koin wird ViewModel in einem Modul über viewModel { } deklariert und im Fragment über by viewModel() bezogen. Die Wahl zwischen Hilt und Koin hängt vom Projekt ab: Hilt bietet Überprüfung des Abhängigkeitsgraphen zur Compile-Zeit, Koin ist leichter und benötigt kein kapt/ksp. Bei IT Sectr verwenden wir Hilt in großen Projekten (mehr als 50 Bildschirme) und Koin in mittleren.
Ein einfaches ViewModel, das einen Integer-Zähler speichert, der bei Bildschirmdrehung nicht zurückgesetzt wird. Demonstriert das grundlegende Muster der Verwendung von MutableLiveData und LiveData.
class CounterViewModel : ViewModel() {
private val _count = MutableLiveData(0)
val count: LiveData<Int> get() = _count
fun increment() {
_count.value = (_count.value ?: 0) + 1
}
fun reset() {
_count.value = 0
}
}
ViewModel, das SavedStateHandle verwendet, um den Zustand automatisch zu erhalten, selbst wenn der Prozess vom System beendet wird. SavedStateHandle ist der einzige Mechanismus, der Daten speichert, wenn die App im Hintergrund minimiert und beendet wird.
class FormViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
val userName = savedStateHandle.getLiveData<String>("userName", "")
val email = savedStateHandle.getLiveData<String>("email", "")
fun saveName(name: String) {
savedStateHandle["userName"] = name
}
fun saveEmail(email: String) {
savedStateHandle["email"] = email
}
}
LiveData von SavedStateHandle speichert automatisch den letzten Wert im Bundle. Bei der Neuerstellung des Prozesses (z. B. nach Minimieren und Schließen der App) wird das Bundle wiederhergestellt, und LiveData erhält den vorherigen Wert. Laut Google-Tests garantiert SavedStateHandle das Speichern von bis zu 5 KB Daten im Bundle — ausreichend für Textfelder, IDs und serialisierte JSON-Objekte.
Häufig gestellte Fragen
ViewModel speichert Daten im RAM des Prozesses — sie sind ohne Serialisierung sofort verfügbar, geeignet für komplexe Objekte (Listen, Bitmap, Netzwerkantworten). onSaveInstanceState() serialisiert Daten in Bundle (maximal 1 MB pro Transaktion ab Android 12) und ist nur für einfache Primitive, String und Serializable/Parcelable geeignet. ViewModel + SavedStateHandle ist die von Google empfohlene Kombination: ViewModel für Laufzeitdaten, SavedStateHandle für die Wiederherstellung bei Prozessbeendigung.
Nein, das System ruft automatisch onCleared() auf, wenn der Scope endet. Manuelle Bereinigung über viewModelStore.clear() ist nur in Tests erforderlich, um Lecks zwischen Testfällen zu verhindern. Im Produktionscode rufen Sie clear() niemals manuell auf — dies unterbricht den ViewModel-Lebenszyklus und kann zu unvorhersehbarem UI-Verhalten führen.
Ja, ViewModel wird in Jetpack Compose über die Funktion viewModel() vollständig unterstützt. In Compose wird ViewModel auf Scope-Ebene des Composable abgerufen und beim Verlassen des Scopes automatisch bereinigt. Die Compose-Version von MVVM heißt Unidirectional Data Flow (UDF): ViewModel veröffentlicht StateFlow, und Composable-Funktionen abonnieren über collectAsState(). Die Compose-Variante des Reducer-Ansatzes ist MVI mit ViewModel.
Verboten ist das Speichern von Verweisen auf Activity, Fragment, View oder Context (außer Application). Dies führt zu Speicherlecks, da ViewModel den UI-Kontext überlebt. Speichern Sie keine serialisierten View-Zustände (z. B. RecyclerView-Position) — verwenden Sie LayoutManager.onSaveInstanceState(). Vermeiden Sie das Speichern großer Datenmengen (mehr als 10 MB) — beim Minimieren des Prozesses gehen Daten ohne SavedStateHandle verloren.
ViewModel wird wie eine normale Kotlin-Klasse ohne Emulator getestet: Instanz erstellen, Methoden aufrufen, Zustand von LiveData oder StateFlow überprüfen. Zum Testen von Coroutinen verwenden Sie runTest aus kotlinx-coroutines-test mit TestDispatcher. Für ViewModel mit Hilt verwenden Sie @HiltViewModelTest und hiltViewModel() in einem Test-Fragment. Laut Google decken Unit-Tests 80–90% der ViewModel-Logik ohne instrumentierte Tests ab.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch