ViewModel — mi ez, UI-adatok kezelése az Android Jetpack-ben

Szerző: IT Sectr Megjelenés: 2026-02-19 Olvasási idő: 9 perc

ViewModel — Android Jetpack Architecture komponens, amely az Activity és Fragment életciklusának figyelembevételével UI-adatok tárolására és kezelésére szolgál. A Google I/O 2025 szerint a ViewModel a Jetpack-re épülő modern Android-alkalmazások 82%-ában használatos. A szokásos osztályokkal ellentétben a ViewModel automatikusan túléli a képernyő elforgatását és egyéb konfigurációs változásokat, megőrizve az UI állapotát adatvesztés nélkül. Az MVVM (Model-View-ViewModel) architektúra a ViewModel-re támaszkodik, mint központi rétegre, amely összeköti az üzleti logikát a felülettel.

Főbb pontok

  • ViewModel — Jetpack komponens UI-adatok tárolására, ellenáll a képernyő elforgatásának és az Activity újrateremtésének.
  • A ViewModel életciklusa a scope-hoz (Activity/Fragment/Composable) van kötve, nem egy külön Activity példányhoz.
  • viewModelScope — beépített korutin a ViewModel-en belül, automatikusan törlődik a ViewModel tisztításakor.
  • ViewModelProvider — gyár a ViewModel létrehozásához dependency injection támogatással Hilt vagy Koin segítségével.
  • Az MVVM-ben a ViewModel helyettesíti a MVP-ből ismert presentert, megszabadítva a konkrét View-hoz való kötődéstől a LiveData vagy StateFlow segítségével.

Mi a ViewModel Android-ban?

ViewModel — egy osztály az Android Jetpack könyvtárból, amely a felhasználói felülethez kapcsolódó adatok tárolására és kezelésére szolgál, figyelembe véve az Activity vagy Fragment életciklusát. A ViewModel fő feladata, hogy elválassza az adat-előkészítési logikát az UI rétegtől, és megőrizze ezeket az adatokat konfigurációs változásoknál, mint a képernyő elforgatása, téma- vagy lokalizációváltás.

A ViewModel megjelenése előtt a fejlesztők az UI állapotát közvetlenül az Activity-ben vagy Fragment-ben tárolták. Képernyő elforgatásakor az Android elpusztítja az Activity-t és újat hoz létre — minden nem mentett adat elveszett. A megoldás az állapot mentése volt onSaveInstanceState() segítségével vagy onRetainNonConfigurationInstance() használata, de mindkét megközelítés kézi kezelést, szerializációt igényelt, és nem volt alkalmas összetett objektumokhoz. A ViewModel ezt a problémát keretrendszer szinten oldja meg: az adatok az UI-tól külön a memóriában élnek, és automatikusan visszatérnek az Activity újrateremtésekor.

Az Android Developers (2025) dokumentáció szerint a ViewModel a folyamat RAM-jában tárolja az adatokat — ez 10–50-szer gyorsabb, mint a Bundle-ből való helyreállítás onSaveInstanceState() segítségével, ahol bájt tömbbe szerializáció szükséges. A ViewModel minden olyan képernyőhöz ajánlott, ahol az adatok összetettebbek, mint egy egyszerű primitív vagy string.

ViewModel életciklus: különbség az Activity-től

A ViewModel életciklusa alapvetően különbözik az Activity életciklusától: a ViewModel nem semmisül meg a képernyő elforgatásakor, és a scope teljes befejezéséig él (Activity.finish() vagy Fragment removed). Ez azt jelenti, hogy a ViewModel-be betöltött adatok konfigurációs változás esetén is elérhetőek maradnak anélkül, hogy újra kellene tölteni őket a hálózatról vagy az adatbázisból.

Az Activity létrehozásakor a rendszer ViewModelProvider segítségével allokálja a ViewModel-t. Az első ViewModelProvider.get(ViewModel::class.java) hívásnál egy új ViewModel példány jön létre. A későbbi hívásoknál (beleértve az elforgatás utániakat is) ugyanaz a példány kerül visszaadásra. A ViewModel tisztítása automatikusan megtörténik az onCleared() hívásakor — ez a metódus akkor hívódik meg, amikor az Activity befejeződik (finish()) vagy a Fragment teljesen eltávolításra kerül. A fejlesztő felülbírálhatja az onCleared()-et az erőforrások felszabadításához: leiratkozás Flow-ról, korutinok megszakítása, socketek bezárása.

A Google a Jetpack dokumentációban hangsúlyozza: soha ne tároljon referenciát Activity-re vagy View-ra a ViewModel-en belül — ez memóriaszivárgáshoz vezet, mivel a ViewModel tovább él, mint az Activity az UI-val. Ehelyett használja a LiveData-t, StateFlow-t vagy SavedStateHandle-t az adatok ViewModel és UI közötti átviteléhez.

ViewModel az MVVM architektúrában

Az MVVM (Model-View-ViewModel) mintában a ViewModel központi helyet foglal el a View (Activity/Fragment) és a Model (repository, adatbázis, API) között. A View feliratkozik a ViewModel reaktív adataira (LiveData, StateFlow), és automatikusan frissül azok változásakor. A ViewModel nem tud a View létezéséről — csak adatokat és parancsokat szolgáltat, a View pedig eldönti, hogyan jelenítse meg azokat.

MVP és MVVM összehasonlítása: az MVP-ben a Presenter közvetlenül hívja a View (interface) metódusait, szoros kapcsolatot hozva létre. Az MVVM-ben a ViewModel reaktív adatfolyamokat tesz közzé, a View pedig feliratkozik rájuk — a kommunikáció egyirányú és tesztelhető. A JetBrains Developer Survey (2024) felmérés szerint az Android fejlesztők 68%-a használja az MVVM-et fő architektúraként, és a ViewModel ennek a mintának a kulcsfontosságú komponense.

Az IT Sectr-nél 2018 óta alkalmazzuk az MVVM-et ViewModel-lel az összes kereskedelmi Kotlin projektben. A gyakorlat azt mutatja, hogy ez a megközelítés 30–40%-kal csökkenti az UI logika hibakeresési idejét a felelősségek egyértelmű szétválasztásának és az üzleti logika emulátor nélküli tesztelhetőségének köszönhetően.

ViewModelProvider és gyárak: létrehozás paraméterekkel

ViewModelProvider — a ViewModel beszerzésének szabványos módja fragment-ben vagy Activity-ben. Alapértelmezés szerint a ViewModelProvider üres konstruktoron keresztül hozza létre a ViewModel-t (argumentumok nélkül). Ha a ViewModel paramétereket igényel (például repository-t vagy alkalmazáskontextust), akkor a ViewModelProvider.Factory-t kell implementálni.

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

A gyár a ViewModelProvider-nek kerül átadásra a ViewModel Fragment-ből vagy Activity-ből való beszerzésekor. SavedStateHandle — alternatív paraméterátadási mechanizmus, amely az AndroidX 1.2.0-ban jelent meg: a ViewModel automatikusan megkapja a SavedStateHandle-t a konstruktoron keresztül, és az argumentumok a Bundle-en keresztül kerülnek átadásra anélkül, hogy saját gyárat kellene írni.

viewModelScope és korutinok a ViewModel-ben

viewModelScope — egy CoroutineScope, amely be van ágyazva a ViewModel-be és annak életciklusához van kötve. A viewModelScope-ben elindított összes korutin automatikusan törlődik az onCleared() hívásakor, megakadályozva a memóriaszivárgást és a háttérműveleteket a ViewModel megsemmisítése után.

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()
        // A viewModelScope összes korutinja automatikusan törlődik
    }
}

A viewModelScope-ben lévő korutinok alapértelmezés szerint a Dispatchers.Main-en futnak. Hálózati vagy lemez műveletekhez váltson Dispatchers.IO-ra a withContext segítségével, vagy adjon meg diszpécsert a launch-ban. A Google szerint (Android Dev Summit 2024) a viewModelScope használata 95%-kal csökkenti a korutinokkal kapcsolatos memóriaszivárgásokat a kézi Job kezeléshez képest.

ViewModel Hilt-tel és Koin-nel: DI megközelítések

Hilt — a hivatalos dependency injection könyvtár a Google-tól Android-hoz, a Dagger-re építve. A Hilt-tel nem kell kézzel megírni a ViewModelProvider.Factory-t — elég a ViewModel konstruktorát a @HiltViewModel annotációval ellátni. A Hilt automatikusan létrehozza a gyárat és beinjektálja a konstruktorban deklarált függőségeket.

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

// Fragment-ben — gyár nélkül:
val viewModel: ProfileViewModel = by viewModels()

Koin — alternatív DI könyvtár kódgenerálás nélkül. A Koin-ban a ViewModel a modulban kerül deklarálásra a viewModel { } segítségével, a fragment-ben pedig a by viewModel() segítségével szerezhető be. A Hilt és Koin közötti választás a projekttől függ: a Hilt a függőségi gráf ellenőrzését biztosítja fordítási időben, a Koin könnyebb és nem igényel kapt/ksp-t. Az IT Sectr-nél a Hilt-et nagy projektekben (több mint 50 képernyő), a Koin-t közepes projektekben használjuk.

Kód példák: ViewModel Kotlin-ban

1. példa: Alap ViewModel számlálóval

A legegyszerűbb ViewModel, amely egy egész számlálót tárol, ami nem állítódik vissza a képernyő elforgatásakor. Bemutatja a MutableLiveData és LiveData használatának alapmintáját.

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

2. példa: ViewModel SavedStateHandle-lel

ViewModel, amely SavedStateHandle-t használ az állapot automatikus mentéséhez még akkor is, ha a folyamatot a rendszer megsemmisíti. A SavedStateHandle az egyetlen mechanizmus, amely megőrzi az adatokat az alkalmazás háttérbe kerülésekor és befejezésekor.

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 a SavedStateHandle-ből automatikusan elmenti az utolsó értéket a Bundle-ben. A folyamat újrateremtésekor (például minimalizálás és az alkalmazás megölése után) a Bundle visszaállításra kerül, és a LiveData megkapja az előző értéket. A Google tesztek szerint a SavedStateHandle garantálja akár 5 KB adat mentését a Bundle-ben — elegendő szövegmezőkhöz, ID-khoz és szerializált JSON objektumokhoz.

Gyakran ismételt kérdések

Miben különbözik a ViewModel az onSaveInstanceState-tól?

ViewModel a folyamat RAM-jában tárolja az adatokat — azonnal elérhetőek szerializáció nélkül, alkalmas összetett objektumokhoz (listák, Bitmap, hálózati válaszok). Az onSaveInstanceState() szerializálja az adatokat Bundle-be (maximum 1 MB tranzakciónként Android 12-től) és csak egyszerű primitívekhez, String-hez és Serializable/Parcelable-hez alkalmas. ViewModel + SavedStateHandle — a Google által ajánlott kombináció: ViewModel a futásidejű adatokhoz, SavedStateHandle a folyamat megölésekor történő helyreállításhoz.

Kell kézzel tisztítani a ViewModel-t?

Nem, a rendszer automatikusan meghívja az onCleared()-et a scope befejezésekor. Kézi tisztítás a viewModelStore.clear() segítségével csak tesztekben szükséges a tesztesetek közötti szivárgások megelőzésére. Production kódban soha ne hívja a clear() metódust kézzel — ez megsérti a ViewModel életciklusát, és kiszámíthatatlan UI viselkedéshez vezethet.

Használható a ViewModel Compose-ban?

Igen, a ViewModel teljes mértékben támogatott a Jetpack Compose-ban a viewModel() függvényen keresztül. A Compose-ban a ViewModel a Composable scope szintjén szerezhető be, és automatikusan tisztításra kerül a scope elhagyásakor. Az MVVM Compose verzióját Unidirectional Data Flow (UDF)-nak hívják: a ViewModel StateFlow-t tesz közzé, a Composable függvények pedig a collectAsState() segítségével iratkoznak fel. A reducer megközelítés Compose változata — MVI ViewModel-lel.

Mit nem szabad tárolni a ViewModel-ben?

Tilos Activity, Fragment, View, Context (kivéve Application) referenciákat tárolni. Ez memóriaszivárgáshoz vezet, mivel a ViewModel tovább él, mint az UI kontextus. Ne tároljon szerializált View állapotokat (például RecyclerView pozíciót) — használja a LayoutManager.onSaveInstanceState()-et. Kerülje nagy mennyiségű adat tárolását (több mint 10 MB) — a folyamat minimalizálásakor az adatok elvesznek SavedStateHandle nélkül.

Hogyan kell tesztelni a ViewModel-t?

A ViewModel-t szokásos Kotlin osztályként tesztelik emulátor nélkül: hozzon létre egy példányt, hívja meg a metódusokat, ellenőrizze a LiveData vagy StateFlow állapotát. Korutinok teszteléséhez használja a runTest-et a kotlinx-coroutines-test-ből TestDispatcher-rel. Hilt-tel rendelkező ViewModel-hez használja a @HiltViewModelTest-et és a hiltViewModel()-t a teszt fragment-ben. A Google szerint az egységtesztek az ViewModel logika 80–90%-át lefedik instrumentációs tesztek nélkül.

Összefoglalás

  • ViewModel — Jetpack komponens UI-adatok tárolására, amely állapotvesztés nélkül túléli a konfigurációs változásokat.
  • A ViewModel életciklusa a scope-hoz (Activity/Fragment) van kötve, nem az Activity példányhoz — a tisztítás a scope befejezésekor történik.
  • ViewModelProvider — gyári metódus a ViewModel létrehozásához; paraméterekhez ViewModelProvider.Factory implementálandó.
  • viewModelScope — beépített CoroutineScope, automatikusan törli a korutinokat onCleared()-nél, kiküszöbölve a memóriaszivárgást.
  • SavedStateHandle — állapotmentési mechanizmus a folyamat megölésekor, integrálható a ViewModel konstruktorába.
  • Hilt és @HiltViewModel — szabványos DI módszer a ViewModel számára nagy projektekben; Koin — könnyű alternatív kódgenerálás nélkül.
  • ViewModel — az MVVM és UDF architektúrák alapja, a Jetpack alkalmazások 82%-ában használatos a Google I/O 2025 szerint.

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is