ViewModel — en Android Jetpack Architecture-komponent avsedd för att lagra och hantera UI-data med hänsyn till Activity och Fragments livscykel. Enligt Google I/O 2025 används ViewModel i 82% av moderna Android-applikationer byggda på Jetpack. Till skillnad från vanliga klasser överlever ViewModel automatiskt skärmrotation och andra konfigurationsändringar, och bevarar UI-tillståndet utan dataförlust. MVVM-arkitekturen (Model-View-ViewModel) förlitar sig på ViewModel som ett centralt lager som kopplar samman affärslogik med gränssnittet.
Huvudpunkter
ViewModel — en klass från Android Jetpack-biblioteket avsedd för att lagra och hantera data relaterade till användargränssnittet, med hänsyn till Activity eller Fragments livscykel. ViewModel: s huvuduppgift är att separera logiken för dataförberedelse från UI-lagret och bevara dessa data vid konfigurationsändringar som skärmrotation, temabyte eller lokalisering.
Innan ViewModel kom lagrade utvecklare UI-tillståndet direkt i Activity eller Fragment. Vid skärmrotation förstör Android Activity och skapar en ny — all osparad data gick förlorad. Lösningen var att spara tillstånd via onSaveInstanceState() eller använda onRetainNonConfigurationInstance(), men båda metoderna krävde manuell hantering, serialisering och var inte lämpliga för komplexa objekt. ViewModel löser detta problem på ramverksnivå: data lever i minnet separat från UI och återkommer automatiskt när Activity återskapas.
Enligt Android Developers-dokumentationen (2025) lagrar ViewModel data i processens RAM — detta är 10–50 gånger snabbare än återställning från Bundle via onSaveInstanceState(), som kräver serialisering till en byte-array. ViewModel rekommenderas för alla skärmar där data är mer komplex än en enkel primitiv eller sträng.
ViewModel: s livscykel skiljer sig fundamentalt från Activitys livscykel: ViewModel förstörs inte vid skärmrotation och lever tills scopet är helt slutfört (Activity.finish() eller Fragment removed). Detta innebär att alla data som laddats in i ViewModel förblir tillgängliga vid konfigurationsändring utan att laddas om från nätverket eller databasen.
I ögonblicket för Activitys skapelse allokerar systemet ViewModel via ViewModelProvider. Vid första anropet av ViewModelProvider.get(ViewModel::class.java) skapas en ny ViewModel-instans. Vid efterföljande anrop (inklusive efter rotation) returneras samma instans. Rensning av ViewModel sker automatiskt vid anrop av onCleared() — denna metod anropas när Activity avslutas (finish()) eller Fragment tas bort helt. Utvecklaren kan åsidosätta onCleared() för att frigöra resurser: avregistrera från Flow, avbryta korutiner, stänga sockets.
Google betonar i Jetpack-dokumentationen: lagra aldrig en referens till Activity eller View inuti ViewModel — detta leder till minnesläckor eftersom ViewModel lever längre än Activity med UI. Använd istället LiveData, StateFlow eller SavedStateHandle för dataöverföring mellan ViewModel och UI.
I mönstret MVVM (Model-View-ViewModel) intar ViewModel en central plats mellan View (Activity/Fragment) och Model (förvar, databas, API). View prenumererar på ViewModel: s reaktiva data (LiveData, StateFlow) och uppdateras automatiskt när de ändras. ViewModel vet inte om View: s existens — den tillhandahåller endast data och kommandon, och View bestämmer hur de ska visas.
Jämförelse mellan MVP och MVVM: i MVP anropar Presenter direkt metoder på View (gränssnitt), vilket skapar en tight koppling. I MVVM publicerar ViewModel reaktiva dataströmmar och View prenumererar på dem — kommunikationen är enkelriktad och testbar. Enligt JetBrains Developer Survey (2024) använder 68% av Android-utvecklarna MVVM som huvudarkitektur, och ViewModel är nyckelkomponenten i detta mönster.
Hos IT Sectr har vi tillämpat MVVM med ViewModel sedan 2018 i alla kommersiella projekt på Kotlin. Praktiken visar att detta tillvägagångssätt minskar felsökningstiden för UI-logik med 30–40% tack vare tydlig ansvarsfördelning och testbarhet av affärslogik utan emulator.
ViewModelProvider — standardmetoden för att få ViewModel i fragment eller Activity. Som standard skapar ViewModelProvider ViewModel via en tom konstruktor (utan argument). Om ViewModel kräver parametrar (till exempel ett förvar eller applikationskontext) måste ViewModelProvider.Factory implementeras.
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
}
}
Fabriken skickas till ViewModelProvider när ViewModel hämtas från Fragment eller Activity. SavedStateHandle — en alternativ mekanism för parameteröverföring som dök upp i AndroidX 1.2.0: ViewModel tar automatiskt emot SavedStateHandle via konstruktorn och argument skickas via Bundle utan att skriva en egen fabrik.
viewModelScope — en CoroutineScope inbäddad i ViewModel och bunden till dess livscykel. Alla korutiner som startas i viewModelScope avbryts automatiskt vid anrop av onCleared(), vilket förhindrar minnesläckor och bakgrundsoperationer efter förstöring av ViewModel.
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()
// Alla korutiner i viewModelScope avbryts automatiskt
}
}
Korutiner i viewModelScope körs som standard på Dispatchers.Main. För nätverks- eller diskoperationer, växla till Dispatchers.IO med withContext eller ange dispatcher i launch. Enligt Google (Android Dev Summit 2024) minskar användning av viewModelScope minnesläckor relaterade till korutiner med 95% jämfört med manuell Job-hantering.
Hilt — Googles officiella dependency injection-bibliotek för Android, byggt på Dagger. Med Hilt behöver du inte skriva ViewModelProvider.Factory manuellt — det räcker att annotera ViewModel-konstruktorn med annoteringen @HiltViewModel. Hilt skapar automatiskt fabriken och injicerar beroenden som deklareras i konstruktorn.
@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")
}
}
}
// I Fragment — utan fabrik:
val viewModel: ProfileViewModel = by viewModels()
Koin — ett alternativt DI-bibliotek utan kodgenerering. I Koin deklareras ViewModel i modulen via viewModel { } och i fragment hämtas den via by viewModel(). Valet mellan Hilt och Koin beror på projektet: Hilt tillhandahåller kontroll av beroendegrafen vid kompilering, Koin är lättare och kräver inte kapt/ksp. Hos IT Sectr använder vi Hilt i stora projekt (mer än 50 skärmar) och Koin i medelstora.
Den enklaste ViewModel som lagrar en heltalsräknare som inte återställs vid skärmrotation. Demonstrerar grundmönstret för användning av MutableLiveData och 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 som använder SavedStateHandle för automatisk tillståndslagring även när processen förstörs av systemet. SavedStateHandle är den enda mekanismen som bevarar data när appen minimeras i bakgrunden och avslutas.
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 från SavedStateHandle sparar automatiskt det senaste värdet i Bundle. När processen återskapas (till exempel efter minimering och dödande av appen) återställs Bundle och LiveData får det föregående värdet. Enligt Google-tester garanterar SavedStateHandle lagring av upp till 5 KB data i Bundle — tillräckligt för textfält, ID:n och serialiserade JSON-objekt.
Vanliga frågor
ViewModel lagrar data i processens RAM — de är omedelbart tillgängliga utan serialisering, lämpliga för komplexa objekt (listor, Bitmap, nätverkssvar). onSaveInstanceState() serialiserar data till Bundle (maximalt 1 MB per transaktion från och med Android 12) och är endast lämplig för enkla primitiver, String och Serializable/Parcelable. ViewModel + SavedStateHandle — rekommenderad kombination från Google: ViewModel för runtime-data, SavedStateHandle för återställning vid processdöd.
Nej, systemet anropar automatiskt onCleared() när scopet slutförs. Manuell rensning via viewModelStore.clear() krävs endast i tester för att förhindra läckor mellan testfall. I produktionskod anropa aldrig clear() manuellt — detta bryter ViewModel: s livscykel och kan leda till oförutsägbart UI-beteende.
Ja, ViewModel stöds fullt ut i Jetpack Compose via funktionen viewModel(). I Compose hämtas ViewModel på Composable-scope nivå och rensas automatiskt när scopet lämnas. Compose-versionen av MVVM kallas Unidirectional Data Flow (UDF): ViewModel publicerar StateFlow och Composable-funktioner prenumererar via collectAsState(). Compose-varianten av reducer-metoden — MVI med ViewModel.
Förbjudet att lagra referenser till Activity, Fragment, View, Context (förutom Application). Detta leder till minnesläckor eftersom ViewModel lever längre än UI-kontexten. Lagra inte serialiserade View-tillstånd (till exempel RecyclerView-position) — använd LayoutManager.onSaveInstanceState(). Undvik att lagra stora mängder data (mer än 10 MB) — vid processminimering går data förlorade utan SavedStateHandle.
ViewModel testas som en vanlig Kotlin-klass utan emulator: skapa en instans, anropa metoder, kontrollera status för LiveData eller StateFlow. För testning av korutiner, använd runTest från kotlinx-coroutines-test med TestDispatcher. För ViewModel med Hilt, använd @HiltViewModelTest och hiltViewModel() i testfragmentet. Enligt Google täcker enhetstester 80–90% av ViewModel-logiken utan instrumentella tester.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också