viewModelScope — bu androidx.lifecycle kutubxonasidan o'rnatilgan CoroutineScope bo'lib, u ViewModel-ning hayotiy sikliga bog'langan va uni tozalashda avtomatik ravishda bekor qilinadi. Google Android Developers, 2025 ma'lumotlariga ko'ra, viewModelScope MVVM arxitekturasida korutinlarni ishga tushirishning standart mexanizmi bo'lib, xotira oqishi xavfisiz asinxron operatsiyalar bilan xavfsiz ishlashni ta'minlaydi. ViewModelScope sukut bo'yicha Dispatchers.Main dan foydalanadi va uning ichidagi barcha IO operatsiyalari withContext orqali bajarilishi kerak.
Asosiy fikrlar
viewModelScope — bu ViewModel interfeysiga extension xususiyati bo'lib, lifecycle-viewmodel-ktx kutubxonasida (2.1.0 versiyasidan boshlab) qo'shilgan. U ViewModel-ning hayotiy sikliga bog'langan tayyor CoroutineScope ni ta'minlaydi.
// Ichki tuzilma (soddalashtirilgan)
val ViewModel.viewModelScope: CoroutineScope
get() {
val scope = this.getTag(JOB_KEY)
if (scope != null) return scope
return CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
.also { setTag(JOB_KEY, it) }
}
Scope birinchi murojaatda dangasa (lazy) tarzda yaratiladi va setTag orqali keshlanadi. SupervisorJob ishlatiladi, ya'ni bitta farzand korutinadagi istisno qolganlarini bekor qilmaydi. Sukut bo'yicha dispetcher Dispatchers.Main.immediate bo'lib, agar chaqiruv allaqachon Main da bo'lsa, qo'shimcha dispetcherizatsiyasiz kodni asosiy oqimda bajaradi.
ViewModel hayotiy siklini tark etganda (Activity tugagan yoki Fragment o'chirilgan), sistem clear() ni chaqiradi, u onCleared() ni ishga tushiradi. Bu callback da viewModelScope o'z Job ini bekor qiladi, bu rekursiv ravishda barcha faol korutinlarni tugatadi. Mexanizm Closeable interfeysi orqali amalga oshiriladi, bunda scope-ning Job i avtomatik yopish uchun resurs sifatida ro'yxatga olinadi.
viewModelScope ning ViewModel-ning hayotiy sikliga bog'lanish mexanizmi teglash va onCleared callback iga asoslanadi. Keling, buni bosqichma-bosqich ko'rib chiqaylik.
ViewModel viewModelScope.launch { ... } ni bajarganida, getter JOB_KEY tegi ostida saqlangan scope mavjudligini tekshiradi. Agar scope hali yaratilmagan bo'lsa — CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) ning yangi nusxasi yaratiladi. Scope ichki teg xaritasi orqali ViewModel ichida saqlanadi.
viewModelScope.launch yoki viewModelScope.async orqali ishga tushirilgan barcha korutinlar SupervisorJob scope iga farzand bo'ladi. Ular asosiy oqimda ishlaydi (agar withContext orqali boshqa dispetcher ko'rsatilmagan bo'lsa). ViewModel tirik ekan — korutinlar faol, to'xtatilgan yoki tugagan bo'lishi mumkin.
Sistem ViewModel ni yo'q qilganda, ViewModel.clear() chaqiriladi. clear() ichida quyidagilar sodir bo'ladi:
Ekran aylantirilganda Activity qayta yaratiladi, ammo ViewModel saqlanadi (ViewModelStoreOwner tufayli). Bu viewModelScope faol qoladi va korutinlar uzilishlarsiz ishlashda davom etadi degani. Activity qayta yaratilgandan so'ng, xuddi shu ViewModel (va xuddi shu scope) qayta ishlatiladi — ma'lumotlarni yuklash qaytadan boshlamaydi.
MVVM (Model-View-ViewModel) — Google tomonidan Android ilovalari uchun tavsiya etilgan arxitekturadir. viewModelScope unda asinxron operatsiyalarni bajaruvchi sifatida markaziy o'rinni egallaydi.
| Qatlam | Komponent | viewModelScope roli |
|---|---|---|
| UI | Activity / Fragment | ViewModel dan StateFlow/LiveData ni kuzatadi |
| ViewModel | ViewModel | viewModelScope orqali korutinlarni ishga tushiradi, UI holatini boshqaradi |
| Repository | Repository | viewModelScope korutinlaridan chaqiriladigan suspend-funksiyalarni qabul qiladi |
| Data | DAO / Api | Haqiqiy so'rovlarni bajaradi (Room, Retrofit) |
ViewModel viewModelScope orqali korutinlarni ishga tushiradi, ularning ichida Repository ning suspend-funksiyalarini chaqiradi. Natija UI qatlami tomonidan kuzatiladigan StateFlow ga aylantiriladi. Bu sxema mas'uliyatlarning aniq bo'linishini va har bir qatlamning mustaqil sinovdan o'tkazilishini ta'minlaydi.
Agar korutinlar Fragment dan ishga tushirilganda, ekran aylantirilganda ular Fragment ning yo'q qilinishi bilan bekor qilinardi. ViewModel rotatsiyadan omon qoladi, shuning uchun uning scope ida ishga tushirilgan korutinlar bajarilishda davom etadi. Bu viewModelScope ning lifecycleScope dan ma'lumotlarni yuklashdagi asosiy ustunligidir.
Kotlin tilidagi Android ilovasida viewModelScope dan foydalanishning uchta amaliy ssenariysini ko'rib chiqamiz.
class ProfileViewModel(
private val repo: ProfileRepository
) : ViewModel() {
private val _profile = MutableStateFlow<Profile?>(null)
val profile: StateFlow<Profile?> = _profile
init {
loadProfile()
}
private fun loadProfile() {
viewModelScope.launch {
val result = repo.getProfile()
_profile.value = result
}
}
}
init blokida darhol profil yuklanishi boshlanadi. Korutina sukut bo'yicha asosiy oqimda bajariladi. Repozitoriy o'zining suspend-funksiyasi ichida tarmoq so'rovi uchun withContext(Dispatchers.IO) dan foydalanadi, shuning uchun ViewModel oqimlarni almashtirish bilan shug'ullanmaydi.
sealed class UiState {
object Loading : UiState()
data class Success(val data: List<Item>) : UiState()
data class Error(val message: String) : UiState()
}
fun fetchItems() {
_state.value = UiState.Loading
viewModelScope.launch {
try {
val items = repo.getItems()
_state.value = UiState.Success(items)
} catch (e: Exception) {
_state.value = UiState.Error(e.message ?: "Unknown error")
}
}
}
UI holati sealed class UiState orqali tasvirlanadi. ViewModel har bir o'zgarishda state ni yangilaydi. Fragment StateFlow ga obuna bo'lib, faqat joriy holatga reaksiya beradi, takroriy rotatsiyalarda eskirgan chaqiruvlarni e'tiborsiz qoldiradi.
private var searchJob: Job? = null
fun search(query: String) {
searchJob?.cancel()
searchJob = viewModelScope.launch {
delay(300)
val results = repo.search(query)
_searchResults.value = results
}
}
Har bir yangi qidiruv so'rovida oldingi korutina bekor qilinadi. delay(300) debounce ni amalga oshiradi — qidiruv faqat kiritishda 300 ms pauzadan keyin bajariladi. Bu server yukini kamaytiradi va eskirgan natijalarning oldini oladi.
Ikkala scope ham AndroidX Lifecycle kutubxonasi tomonidan taqdim etiladi, ammo turli hayotiy sikllarga bog'langan. Ularning o'rtasida tanlov vazifa turiga bog'liq.
| Xususiyat | viewModelScope | lifecycleScope |
|---|---|---|
| Egasi | ViewModel | LifecycleOwner (Activity/Fragment) |
| Rotatsiyada bekor qilish | Yo'q (ViewModel saqlanadi) | Ha (Activity qayta yaratiladi) |
| Sukut bo'yicha dispetcher | Dispatchers.Main.immediate | Dispatchers.Main.immediate |
| Mavjud | ViewModel | Activity, Fragment, Service |
| Oddiy ssenariy | Ma'lumotlarni yuklash, biznes mantiq | UI o'zaro aloqasi, animatsiyalar, snackbarlar |
Google ma'lumotlarni yuklash va qayta ishlash bilan bog'liq barcha vazifalar uchun viewModelScope dan foydalanishni tavsiya qiladi. lifecycleScope UI hayotining aniq bir daqiqasiga bog'liq operatsiyalar uchun qo'llanilishi kerak — masalan, ekranning birinchi paydo bo'lishida animatsiyani ishga tushirish yoki ekrandan chiqishda to'xtatilishi kerak bo'lgan Location yangilanishlariga obuna bo'lish.
Hatto Android ning yaxshi hujjatlangan API larida ham dasturchilar xarakterli xatolarga yo'l qo'yadilar. To'rtta eng ko'p uchraydigan muammoni ko'rib chiqamiz.
Eng makkor xato — ViewModel tozalangandan keyin StateFlow yoki LiveData ni yangilashga urinish. viewModelScope onCleared() da bekor qilingan bo'lsa-da, korutina haqiqiy bekor qilish momentiga qadar kodni bajarishi mumkin. Tekshirish uchun isActive dan foydalaning yoki catch blokining tugashiga ishoning.
viewModelScope ichki SupervisorJob dan foydalanadi, bu xatolarni korutinlar o'rtasida izolyatsiya qiladi. Ammo viewModelScope.launch ichida o'z Job() bilan korutinani ishga tushirsangiz, bu korutina SupervisorJob ga farzand bo'ladi, lekin boshqa korutinlardagi xatolarda bekor qilishdan himoyalanmaydi.
viewModelScope qattiq chegaraga ega bo'lmasa ham, minglab faol korutinlar tizimni sekinlashtirishi mumkin. Uzun ma'lumotlar ro'yxatlari uchun har bir element uchun alohida korutina yaratish o'rniga Flow ni collectLatest bilan ishlating.
Tasodifan viewModelScope o'rniga GlobalScope ni import qilsangiz, korutina ViewModel tozalanganda bekor qilinmaydi. Bu xotira oqishiga va potensial crashga olib keladi. Har doim korutinalarning viewModelScope orqali ishga tushirilganligini tekshiring, ayniqsa meros fragmentlarda.
Tez-tez beriladigan savollar
To'g'ridan-to'g'ri viewModelScope dispetcherini o'zgartirish mumkin emas — u qattiq Dispatchers.Main.immediate qilib o'rnatilgan. Ammo korutina ichida withContext orqali boshqa dispetcherga o'tish mumkin. Testlarda dispetcherini o'zgartirish uchun Rule orqali TestDispatcher dan foydalaning.
Scope ni Repository ga uzatmang — bu arxitektura prinsiplarini buzadi. Repository suspend-funksiyalar taqdim etishi kerak, ViewModel esa viewModelScope orqali korutinlarni o'zi boshqaradi. Agar Repository scope talab qilsa — arxitektura Clean Architecture foydasiga qayta ko'rib chiqing.
SupervisorJob bir korutinadagi istisno (masalan, bir nechta mustaqil so'rovlardan birining yuklanish xatosi) qolgan korutinlarni bekor qilmasligini kafolatlaydi. Bu turli ekranlar mustaqil ma'lumotlarni yuklaydigan ViewModel ssenariysiga mos keladi.
Ha, viewModelScope UI turidan (View System yoki Jetpack Compose) qat'i nazar, har qanday ViewModel da mavjud. Compose da korutinlar ham viewModelScope orqali ishga tushiriladi, UI effektlari uchun esa LaunchedEffect va rememberCoroutineScope ishlatiladi.
viewModelScope.cancel() chaqiruvi scope ni darhol bekor qiladi — barcha faol korutinlar CancellationException bilan tugaydi. Agar bundan keyin viewModelScope.launch ni chaqirsangiz, yangi scope getterga navbatdagi murojaatda avtomatik yaratiladi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.