viewModelScope: bu nədir, ViewModel-ə bağlanması və Android-də işi

Müəllif: IT Sectr Dərc olunub: 2026-06-23 Oxuma vaxtı: 9 dəq

viewModelScope — bu, androidx.lifecycle kitabxanasından daxili CoroutineScope-dir. O, ViewModel-in həyat dövrünə bağlanır və təmizlənmə zamanı avtomatik olaraq ləğv edilir. Google Android Developers, 2025-ə görə, viewModelScope MVVM arxitekturasında korutinlərin işə salınması üçün standart mexanizmdir. O, yaddaş sızması riski olmadan asinxron əməliyyatlarla təhlükəsiz işləməyi təmin edir. ViewModelScope defolt olaraq Dispatchers.Main istifadə edir və onun daxilindəki bütün IO əməliyyatları withContext vasitəsilə yerinə yetirilməlidir.

Əsas məqamlar

  • viewModelScope — lifecycle-viewmodel-ktx-dən CoroutineScope, ViewModel-in onCleared() metodunda ləğv edilir
  • Dispatchers.Main — defolt dispatcher, buna görə korutinlər daxilində UI yeniləmələri təhlükəsizdir
  • onCleared — callback, çağırıldıqda viewModelScope bütün aktiv korutinləri avtomatik ləğv edir
  • clear() vs onCleared() — clear() framework tərəfindən onCleared-dən əvvəl çağırılır, bu da scope-un ləğvini təmin edir
  • launch — viewModelScope-da fire-and-forget əməliyyatları üçün əsas korutin başlatma üsulu

Android-də viewModelScope nədir?

viewModelScope — bu, lifecycle-viewmodel-ktx kitabxanasında (2.1.0 versiyasından) əlavə edilmiş ViewModel interfeysinə extension-xüsusiyyətdir. O, ViewModel-in həyat dövrünə bağlanmış hazır CoroutineScope təmin edir.

kotlin
// Daxili struktur (sadələşdirilmiş)
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 ilk müraciətdə tənbəl (lazy) şəkildə yaradılır və setTag vasitəsilə keşlənir. SupervisorJob istifadə olunur, yəni bir uşaq korutindəki istisna qalanlarını ləğv etmir. Defolt dispatcher Dispatchers.Main.immediate-dir, o, əgər çağırış artıq Main-dədirsə, əlavə dispetçerizasiya olmadan kodu əsas axında yerinə yetirir.

viewModelScope təmizlənmə barədə bildirişi necə alır

ViewModel həyat dövrünü tərk etdikdə (Activity tamamlandıqda və ya Fragment silindikdə), sistem clear() çağırır, o da onCleared()-ı işə salır. Bu callback-də viewModelScope öz Job-unu ləğv edir, bu da rekursiv olaraq bütün aktiv korutinləri bitirir. Mexanizm Closeable interfeysi vasitəsilə həyata keçirilir, burada scope-un Job-ı avtomatik bağlanma üçün resurs kimi qeydiyyatdan keçirilir.

viewModelScope necə işləyir: ViewModel-in həyat dövrünə bağlanması

viewModelScope-un ViewModel-in həyat dövrünə bağlanma mexanizmi teqləmə və onCleared callback-inə əsaslanır. Bunun addım-addım necə işlədiyinə baxaq.

Addım 1: İlk müraciətdə scope-un yaradılması

ViewModel viewModelScope.launch { ... } yerinə yetirdikdə, getter JOB_KEY teqi altında saxlanılmış scope-un olub-olmadığını yoxlayır. Scope hələ yaradılmayıbsa — CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)-nin yeni nüsxəsi yaradılır. Scope daxili teq map-i vasitəsilə ViewModel daxilində saxlanılır.

Addım 2: Korutinlərin həyat dövrü

viewModelScope.launch və ya viewModelScope.async vasitəsilə işə salınmış bütün korutinlər SupervisorJob scope-na uşaq olurlar. Onlar əsas axında işləyirlər (əgər withContext vasitəsilə başqa dispatcher göstərilməyibsə). ViewModel yaşadığı müddətcə — korutinlər aktiv, dayandırılmış və ya bitmiş ola bilər.

Addım 3: onCleared zamanı ləğv

Sistem ViewModel-i məhv etdikdə, ViewModel.clear() çağırılır. clear() daxilində aşağıdakılar baş verir:

  • İstifadəçi məntiqi üçün onCleared() çağırışı
  • addCloseable vasitəsilə qeydiyyatdan keçmiş bütün Closeable resurslarının bağlanması
  • viewModelScope Job-ı Cancelled vəziyyətinə keçir
  • Bütün uşaq korutinlər rekursiv ləğv edilir
  • Zibil yığan üçün scope-a istinadların azad edilməsi

Ekran rotasiyasına davamlılıq

Ekran çevrildikdə Activity yenidən yaradılır, lakin ViewModel saxlanılır (ViewModelStoreOwner sayəsində). Bu o deməkdir ki, viewModelScope aktiv qalır və korutinlər kəsintisiz işləməyə davam edir. Activity yenidən yaradıldıqdan sonra eyni ViewModel (və eyni scope) təkrar istifadə olunur — məlumat yüklənməsi yenidən başlamır.

MVVM arxitekturasında viewModelScope

MVVM (Model-View-ViewModel) — Google tərəfindən Android proqramları üçün tövsiyə olunan arxitekturadır. viewModelScope burada asinxron əməliyyatların icraçısı kimi mərkəzi yer tutur.

viewModelScope-un arxitektura qatlarında rolu

QatKomponentviewModelScope-un rolu
UIActivity / FragmentViewModel-dən StateFlow/LiveData-nı müşahidə edir
ViewModelViewModelviewModelScope vasitəsilə korutinləri işə salır, UI vəziyyətini idarə edir
RepositoryRepositoryviewModelScope korutinlərindən çağırılan suspend-funksiyaları qəbul edir
DataDAO / ApiFaktiki sorğuları yerinə yetirir (Room, Retrofit)

ViewModel viewModelScope vasitəsilə korutinləri işə salır, onların daxilində Repository-nin suspend-funksiyalarını çağırır. Nəticə UI qatı tərəfindən müşahidə olunan StateFlow-a çevrilir. Bu sxem məsuliyyətlərin aydın bölünməsini və hər bir qatın müstəqil sınaqdan keçirilməsini təmin edir.

Niyə viewModelScope ViewModel-də, Fragment-də yox

Əgər korutinlər Fragment-dən işə salınsaydı, ekran çevrildikdə onlar Fragment-in məhv edilməsi ilə birlikdə ləğv olunardı. ViewModel rotasiyadan sağ çıxır, buna görə də onun scope-da işə salınmış korutinlər işləməyə davam edir. Bu, məlumat yükləmə zamanı viewModelScope-un lifecycleScope qarşısında əsas üstünlüyüdür.

viewModelScope istifadə nümunələri

Kotlin dilində Android proqramında viewModelScope-dan istifadənin üç praktik ssenarisini nəzərdən keçirək.

Nümunə 1: ViewModel yaradılarkən məlumatların yüklənməsi

kotlin
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 blokunda dərhal profil yüklənməsi başlayır. Korutina defolt olaraq əsas axında işləyir. Repozitori öz suspend-funksiyası daxilində şəbəkə sorğusu üçün withContext(Dispatchers.IO) istifadə edir, buna görə ViewModel axınların dəyişdirilməsi ilə məşğul olmur.

Nümunə 2: Səhvlərin sealed class vasitəsilə işlənməsi

kotlin
sealed class UiState {
    object Loading : UiState()
    data class Success(val data: List<Item>) : UiState()
    data class Error(val message: String) : UiState()
}
kotlin
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 vəziyyəti sealed class UiState vasitəsilə təsvir olunur. ViewModel hər dəyişiklikdə state-i yeniləyir. Fragment StateFlow-a abunə olub yalnız aktual vəziyyətə reaksiya verir, təkrar rotasiyalarda köhnəlmiş çağırışları nəzərə almır.

Nümunə 3: Yeni sorğuda əvvəlki korutinanın ləğvi

kotlin
private var searchJob: Job? = null

fun search(query: String) {
    searchJob?.cancel()
    searchJob = viewModelScope.launch {
        delay(300)
        val results = repo.search(query)
        _searchResults.value = results
    }
}

Hər yeni axtarış sorğusunda əvvəlki korutina ləğv edilir. delay(300) debounce-u həyata keçirir — axtarış yalnız daxil etmədə 300 ms fasilədən sonra yerinə yetirilir. Bu, server yükünü azaldır və köhnəlmiş nəticələrin qarşısını alır.

viewModelScope vs lifecycleScope: nə vaxt hansı seçilməlidir

Hər iki scope AndroidX Lifecycle kitabxanası tərəfindən təmin edilir, lakin müxtəlif həyat dövrlərinə bağlıdır. Onların arasında seçim tapşırığın növündən asılıdır.

Scope-ların müqayisəsi

XüsusiyyətviewModelScopelifecycleScope
SahibiViewModelLifecycleOwner (Activity/Fragment)
Rotasiyada ləğvXeyr (ViewModel saxlanılır)Bəli (Activity yenidən yaradılır)
Defolt dispatcherDispatchers.Main.immediateDispatchers.Main.immediate
Harada mövcuddurViewModelActivity, Fragment, Service
Tip ssenariMəlumat yükləmə, biznes məntiqiUI qarşılıqlı əlaqəsi, animasiyalar, snackbarlar

Google tövsiyələri

Google məlumatların yüklənməsi və işlənməsi ilə bağlı bütün tapşırıqlar üçün viewModelScope-dan istifadə etməyi tövsiyə edir. lifecycleScope UI-nin konkret anına bağlı əməliyyatlar üçün tətbiq edilməlidir — məsələn, ekranın ilk görünməsi zamanı animasiyanın başladılması və ya ekrandan çıxışda dayandırılmalı olan Location yeniləmələrinə abunəlik.

viewModelScope ilə işləyərkən tipik səhvlər

Hətta Android-in yaxşı sənədləşdirilmiş API-lərində belə tərtibatçılar xarakterik səhvlərə yol verirlər. Dörd ən çox rast gəlinən problemi nəzərdən keçirək.

Səhv 1: Scope ləğv edildikdən sonra UI-nin yenilənməsi

Ən məkrli səhv — ViewModel təmizləndikdən sonra StateFlow və ya LiveData-nı yeniləməyə cəhd etməkdir. viewModelScope onCleared() zamanı ləğv edilsə də, korutina faktiki ləğv anına qədər kodu yerinə yetirə bilər. Yoxlamaq üçün isActive istifadə edin və ya catch blokunun tamamlanmasına güvənin.

Səhv 2: SupervisorJob nəzərə alınmadan korutinlərin işə salınması

viewModelScope daxildə SupervisorJob istifadə edir ki, bu da səhvləri korutinlər arasında izolyasiya edir. Amma viewModelScope.launch daxilində öz Job() ilə korutina işə salsanız, həmin korutina SupervisorJob-a uşaq olacaq, lakin digər korutinlərdəki səhvlər zamanı ləğvdən qorunmayacaq.

Səhv 3: Bir scope-da çox sayda korutina

viewModelScope-un sərt limiti olmasa da, minlərlə aktiv korutina sistemi ləngidə bilər. Uzun məlumat siyahıları üçün hər element üçün ayrıca korutina yaratmaq əvəzinə Flow ilə collectLatest istifadə edin.

Səhv 4: viewModelScope əvəzinə GlobalScope istifadəsi

Təsadüfən viewModelScope əvəzinə GlobalScope idxal etsəniz, korutina ViewModel təmizlənərkən ləğv edilməyəcək. Bu, yaddaş sızmasına və potensial crash-a səbəb olacaq. Həmişə korutinlərin viewModelScope vasitəsilə işə salındığını yoxlayın, xüsusilə varis fragmentlərdə.

Tez-tez verilən suallar

viewModelScope-un defolt dispatcherini dəyişmək olarmı?

Birbaşa viewModelScope-un dispatcherini dəyişmək olmaz — o, Dispatchers.Main.immediate kimi sərt şəkildə təyin edilib. Amma korutina daxilində withContext vasitəsilə başqa dispatcherə keçmək olar. Testlərdə dispatcheri dəyişmək üçün Rule vasitəsilə TestDispatcher istifadə edin.

viewModelScope-u Repository-ə necə ötürmək olar?

Scope-u Repository-ə ötürməyin — bu arxitektura prinsiplərini pozur. Repository suspend-funksiyalar təmin etməli, ViewModel isə viewModelScope vasitəsilə korutinləri özü idarə etməlidir. Əgər Repository scope tələb edirsə — arxitekturanı Clean Architecture lehinə yenidən nəzərdən keçirin.

Niyə viewModelScope SupervisorJob istifadə edir?

SupervisorJob bir korutindəki istisnanın (məsələn, bir neçə müstəqil sorğudan birinin yüklənmə xətası) qalan korutinləri ləğv etməməsinə zəmanət verir. Bu, müxtəlif ekranların müstəqil məlumatlar yüklədiyi ViewModel ssenarisinə uyğundur.

viewModelScope Jetpack Compose-da mövcuddurmu?

Bəli, viewModelScope UI növündən (View System və ya Jetpack Compose) asılı olmayaraq istənilən ViewModel-də mövcuddur. Compose-da korutinlər də viewModelScope vasitəsilə işə salınır, UI effektləri üçün isə LaunchedEffectrememberCoroutineScope istifadə olunur.

viewModelScope.cancel() çağırıldıqda korutinə nə olur?

viewModelScope.cancel() çağırışı scope-u dərhal ləğv edir — bütün aktiv korutinlər CancellationException ilə bitir. Bundan sonra viewModelScope.launch çağırsanız, yeni scope getterə növbəti müraciətdə avtomatik yaradılacaq.

Nəticə

  • viewModelScope — ViewModel-in həyat dövrünə bağlanmış və onCleared() zamanı avtomatik ləğv edilən CoroutineScope
  • SupervisorJob + Dispatchers.Main — səhvlərin izolyasiyasını və UI-ə təhlükəsiz girişi təmin edən daxili konfiqurasiya
  • Ekran rotasiyası — ViewModel saxlanılır, buna görə viewModelScope-dakı korutinlər yenidən başlamadan işləməyə davam edir
  • MVVM arxitekturası — viewModelScope ViewModel qatında asinxron əməliyyatlar üçün mərkəzi elementdir
  • lifecycleScope — ViewModel deyil, Activity/Fragment həyat dövrünə bağlı əməliyyatlar üçün alternativ
  • StateFlow — viewModelScope korutinlərindən UI-ə sealed class vasitəsilə məlumat ötürmənin üstünlük verilən üsulu
  • GlobalScope təhlükəlidir — viewModelScope-u GlobalScope ilə əvəz etmək yaddaş sızmalarına və proqram çökmələrinə səbəb olur

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun