ViewModel — wat is het, UI-gegevens beheren in Android Jetpack

Auteur: IT Sectr Gepubliceerd: 2026-02-19 Leestijd: 9 min

ViewModel — een Android Jetpack Architecture-component voor het opslaan en beheren van UI-gegevens rekening houdend met de levenscyclus van Activity en Fragment. Volgens Google I/O 2025 wordt ViewModel gebruikt in 82% van de moderne Android-apps gebouwd op Jetpack. In tegenstelling tot gewone klassen overleeft ViewModel automatisch schermrotatie en andere configuratiewijzigingen, behoudend de UI-status zonder gegevensverlies. De MVVM-architectuur (Model-View-ViewModel) vertrouwt op ViewModel als centrale laag die bedrijfslogica met de interface verbindt.

Belangrijkste punten

  • ViewModel — Jetpack-component voor het opslaan van UI-gegevens, bestand tegen schermrotatie en het opnieuw aanmaken van Activity.
  • De levenscyclus van ViewModel is gekoppeld aan de scope (Activity/Fragment/Composable), niet aan een afzonderlijke Activity-instantie.
  • viewModelScope — ingebouwde coroutine in ViewModel, automatisch geannuleerd bij het opschonen van ViewModel.
  • ViewModelProvider — fabriek voor het maken van ViewModel met ondersteuning voor dependency injection via Hilt of Koin.
  • In MVVM vervangt ViewModel de presenter uit MVP, waardoor binding aan een specifieke View via LiveData of StateFlow wordt geëlimineerd.

Wat is ViewModel in Android?

ViewModel — een klasse uit de Android Jetpack-bibliotheek voor het opslaan en beheren van gegevens die aan de gebruikersinterface zijn gekoppeld, rekening houdend met de levenscyclus van Activity of Fragment. De belangrijkste taak van ViewModel is het scheiden van de gegevensvoorbereidingslogica van de UI-laag en het behouden van deze gegevens bij configuratiewijzigingen zoals schermrotatie, themawijziging of lokalisatie.

Vóór de komst van ViewModel slaan ontwikkelaars de UI-status rechtstreeks op in de Activity of Fragment. Bij schermrotatie vernietigt Android de Activity en maakt een nieuwe aan — alle niet-opgeslagen gegevens gingen verloren. De oplossing was statusopslag via onSaveInstanceState() of het gebruik van onRetainNonConfigurationInstance(), maar beide benaderingen vereisten handmatig beheer, serialisatie en waren niet geschikt voor complexe objecten. ViewModel lost dit probleem op framework-niveau op: gegevens leven in het geheugen gescheiden van de UI en worden automatisch teruggegeven bij het opnieuw aanmaken van de Activity.

Volgens de Android Developers-documentatie (2025) slaat ViewModel gegevens op in het RAM van het proces — dit is 10–50 keer sneller dan herstel uit Bundle via onSaveInstanceState(), waar serialisatie naar een byte-array nodig is. ViewModel wordt aanbevolen voor alle schermen waar gegevens complexer zijn dan een eenvoudig primitief of string.

Levenscyclus van ViewModel: verschil met Activity

De levenscyclus van ViewModel verschilt fundamenteel van de levenscyclus van Activity: ViewModel wordt niet vernietigd bij schermrotatie en leeft tot de volledige voltooiing van de scope (Activity.finish() of Fragment removed). Dit betekent dat alle gegevens die in ViewModel zijn geladen, beschikbaar blijven bij configuratiewijzigingen zonder opnieuw laden uit het netwerk of de database.

Op het moment van het aanmaken van de Activity wijst het systeem ViewModel toe via ViewModelProvider. Bij de eerste aanroep van ViewModelProvider.get(ViewModel::class.java) wordt een nieuwe ViewModel-instantie gemaakt. Bij volgende aanroepen (ook na rotatie) wordt dezelfde instantie teruggegeven. Het opschonen van ViewModel gebeurt automatisch bij het aanroepen van onCleared() — deze methode wordt aangeroepen wanneer de Activity wordt beëindigd (finish()) of Fragment volledig wordt verwijderd. De ontwikkelaar kan onCleared() overschrijven om bronnen vrij te geven: uitschrijven van Flow, annuleren van coroutines, sluiten van sockets.

Google benadrukt in de Jetpack-documentatie: sla nooit een verwijzing naar Activity of View op in ViewModel — dit leidt tot geheugenlekken omdat ViewModel langer leeft dan de Activity met UI. Gebruik in plaats daarvan LiveData, StateFlow of SavedStateHandle voor gegevensoverdracht tussen ViewModel en UI.

ViewModel in de MVVM-architectuur

In het MVVM (Model-View-ViewModel)-patroon neemt ViewModel de centrale plaats in tussen View (Activity/Fragment) en Model (repository, database, API). View abonneert zich op de reactieve gegevens van ViewModel (LiveData, StateFlow) en wordt automatisch bijgewerkt wanneer deze veranderen. ViewModel weet niet van het bestaan van View — het levert alleen gegevens en opdrachten, en View beslist hoe deze worden weergegeven.

Vergelijking van MVP en MVVM: in MVP roept Presenter rechtstreeks methoden van View (interface) aan, waardoor een strakke koppeling ontstaat. In MVVM publiceert ViewModel reactieve gegevensstromen en View abonneert zich erop — communicatie is eenrichtingsverkeer en testbaar. Volgens de JetBrains Developer Survey (2024) gebruikt 68% van de Android-ontwikkelaars MVVM als belangrijkste architectuur, en ViewModel is de sleutelcomponent van dit patroon.

Bij IT Sectr passen we MVVM met ViewModel sinds 2018 toe in alle commerciële projecten op Kotlin. De praktijk leert dat deze aanpak de tijd voor het debuggen van UI-logica met 30–40% verkort dankzij duidelijke scheiding van verantwoordelijkheden en testbaarheid van bedrijfslogica zonder emulator.

ViewModelProvider en fabrieken: maken met parameters

ViewModelProvider — de standaard manier om een ViewModel te verkrijgen in een fragment of Activity. Standaard maakt ViewModelProvider een ViewModel via een lege constructor (zonder argumenten). Als ViewModel parameters nodig heeft (bijvoorbeeld een repository of applicatiecontext), moet ViewModelProvider.Factory worden geïmplementeerd.

kotlin
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
    }
}

De fabriek wordt doorgegeven aan ViewModelProvider bij het verkrijgen van de ViewModel uit Fragment of Activity. SavedStateHandle — een alternatief mechanisme voor parameteroverdracht, verschenen in AndroidX 1.2.0: ViewModel ontvangt automatisch SavedStateHandle via de constructor en argumenten worden via Bundle doorgegeven zonder het schrijven van een eigen fabriek.

viewModelScope en coroutines in ViewModel

viewModelScope — een CoroutineScope ingebouwd in ViewModel en gekoppeld aan zijn levenscyclus. Alle coroutines die in viewModelScope worden gestart, worden automatisch geannuleerd bij het aanroepen van onCleared(), wat geheugenlekken en achtergrondbewerkingen na vernietiging van ViewModel voorkomt.

kotlin
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 coroutines van viewModelScope worden automatisch geannuleerd
    }
}

Coroutines in viewModelScope worden standaard uitgevoerd op Dispatchers.Main. Schakel voor netwerk- of schijfbewerkingen over naar Dispatchers.IO met withContext of geef een dispatcher op in launch. Volgens Google (Android Dev Summit 2024) vermindert het gebruik van viewModelScope geheugenlekken gerelateerd aan coroutines met 95% in vergelijking met handmatig Job-beheer.

ViewModel met Hilt en Koin: DI-benaderingen

Hilt — de officiële dependency injection-bibliotheek van Google voor Android, gebouwd op Dagger. Met Hilt hoeft u ViewModelProvider.Factory niet handmatig te schrijven — het is voldoende om de ViewModel-constructor te annoteren met @HiltViewModel. Hilt maakt automatisch de fabriek aan en injecteert de in de constructor gedeclareerde afhankelijkheden.

kotlin
@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")
        }
    }
}

// In Fragment — zonder fabriek:
val viewModel: ProfileViewModel = by viewModels()

Koin — een alternatieve DI-bibliotheek zonder codegeneratie. In Koin wordt ViewModel gedeclareerd in de module via viewModel { } en in fragment verkregen via by viewModel(). De keuze tussen Hilt en Koin hangt af van het project: Hilt biedt controle van de afhankelijkheidsgraaf tijdens compilatie, Koin is lichter en vereist geen kapt/ksp. Bij IT Sectr gebruiken we Hilt in grote projecten (meer dan 50 schermen) en Koin in middelgrote projecten.

Codevoorbeelden: ViewModel in Kotlin

Voorbeeld 1: Basis ViewModel met teller

De eenvoudigste ViewModel die een integer-teller opslaat die niet wordt gereset bij schermrotatie. Demonstreert het basispatroon van het gebruik van MutableLiveData en LiveData.

kotlin
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
    }
}

Voorbeeld 2: ViewModel met SavedStateHandle

ViewModel die SavedStateHandle gebruikt voor automatische statusopslag, zelfs bij vernietiging van het proces door het systeem. SavedStateHandle is het enige mechanisme dat gegevens behoudt bij het minimaliseren van de app naar de achtergrond en het beëindigen ervan.

kotlin
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 uit SavedStateHandle slaat automatisch de laatste waarde op in Bundle. Bij het opnieuw aanmaken van het proces (bijvoorbeeld na minimaliseren en doden van de app) wordt Bundle hersteld en ontvangt LiveData de vorige waarde. Volgens Google-tests garandeert SavedStateHandle het behoud van tot 5 KB aan gegevens in Bundle — voldoende voor tekstvelden, ID's en geserialiseerde JSON-objecten.

Veelgestelde vragen

Waarin verschilt ViewModel van onSaveInstanceState?

ViewModel slaat gegevens op in het RAM van het proces — ze zijn direct beschikbaar zonder serialisatie, geschikt voor complexe objecten (lijsten, Bitmap, netwerkantwoorden). onSaveInstanceState() serialiseert gegevens naar Bundle (maximaal 1 MB per transactie vanaf Android 12) en is alleen geschikt voor eenvoudige primitieven, String en Serializable/Parcelable. ViewModel + SavedStateHandle — de door Google aanbevolen combinatie: ViewModel voor runtime-gegevens, SavedStateHandle voor herstel bij het doden van het proces.

Moet ViewModel handmatig worden opgeschoond?

Nee, het systeem roept automatisch onCleared() aan bij voltooiing van de scope. Handmatig opschonen via viewModelStore.clear() is alleen nodig in tests om lekken tussen testgevallen te voorkomen. In productiecode nooit clear() handmatig aanroepen — dit schendt de levenscyclus van ViewModel en kan leiden tot onvoorspelbaar UI-gedrag.

Kan ViewModel worden gebruikt in Compose?

Ja, ViewModel wordt volledig ondersteund in Jetpack Compose via de functie viewModel(). In Compose wordt ViewModel verkregen op het niveau van de Composable-scope en automatisch opgeschoond bij het verlaten van de scope. De Compose-versie van MVVM heet Unidirectional Data Flow (UDF): ViewModel publiceert StateFlow en Composable-functies abonneren zich via collectAsState(). De Compose-variant van de reducer-benadering — MVI met ViewModel.

Wat mag niet worden opgeslagen in ViewModel?

Het is verboden verwijzingen naar Activity, Fragment, View, Context (behalve Application) op te slaan. Dit leidt tot geheugenlekken omdat ViewModel langer leeft dan de UI-context. Bewaar geen geserialiseerde View-toestanden (bijvoorbeeld RecyclerView-positie) — gebruik LayoutManager.onSaveInstanceState(). Vermijd het opslaan van grote hoeveelheden gegevens (meer dan 10 MB) — bij minimaliseren van het proces gaan gegevens verloren zonder SavedStateHandle.

Hoe test je ViewModel?

ViewModel wordt getest als een gewone Kotlin-klasse zonder emulator: maak een instantie, roep methoden aan, controleer de status van LiveData of StateFlow. Gebruik voor het testen van coroutines runTest uit kotlinx-coroutines-test met TestDispatcher. Gebruik voor ViewModel met Hilt @HiltViewModelTest en hiltViewModel() in het testfragment. Volgens Google dekken unittesten 80–90% van de ViewModel-logica zonder instrumentele tests.

Samenvatting

  • ViewModel — Jetpack-component voor het opslaan van UI-gegevens, die configuratiewijzigingen overleeft zonder statusverlies.
  • De levenscyclus van ViewModel is gekoppeld aan de scope (Activity/Fragment), niet aan de Activity-instantie — opschoning vindt plaats bij voltooiing van de scope.
  • ViewModelProvider — fabrieksmethode voor het maken van ViewModel; voor parameters wordt ViewModelProvider.Factory geïmplementeerd.
  • viewModelScope — ingebouwde CoroutineScope, die coroutines automatisch annuleert bij onCleared(), wat geheugenlekken elimineert.
  • SavedStateHandle — mechanisme voor statusopslag bij het doden van het proces, integreerbaar in de ViewModel-constructor.
  • Hilt en @HiltViewModel — standaard DI-methode voor ViewModel in grote projecten; Koin — lichtgewicht alternatief zonder codegeneratie.
  • ViewModel — de basis van MVVM- en UDF-architecturen, gebruikt in 82% van de Jetpack-apps volgens Google I/O 2025.

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook