viewModelScope: nedir, ViewModel'e bağlanma ve Android'de çalışma

Yazar: IT Sectr Yayınlanma: 2026-06-23 Okuma süresi: 9 dk

viewModelScope, androidx.lifecycle kütüphanesinden gelen, ViewModel yaşam döngüsüne bağlı ve temizlendiğinde otomatik olarak iptal edilen yerleşik bir CoroutineScope'tur. Google Android Developers, 2025'e göre viewModelScope, MVVM mimarisinde coroutine başlatmak için standart mekanizmadır ve bellek sızıntısı riski olmadan güvenli asenkron işlemler sağlar. ViewModelScope varsayılan olarak Dispatchers.Main kullanır ve içindeki tüm IO işlemleri withContext aracılığıyla yürütülmelidir.

Önemli Noktalar

  • viewModelScope — lifecycle-viewmodel-ktx'ten CoroutineScope, ViewModel.onCleared() çağrıldığında iptal edilir
  • Dispatchers.Main — varsayılan dağıtıcı, bu nedenle coroutine'ler içindeki UI güncellemeleri güvenlidir
  • onCleared — viewModelScope'taki tüm aktif coroutine'leri otomatik olarak iptal eden geri çağrı
  • clear() vs onCleared() — clear() framework tarafından onCleared'dan önce çağrılır, scope iptalini garanti eder
  • launch — fire-and-forget işlemleri için viewModelScope'ta coroutine başlatmanın ana yolu

Android'de viewModelScope nedir?

viewModelScope, ViewModel arayüzünde bir extension özelliğidir ve lifecycle-viewmodel-ktx kütüphanesine (sürüm 2.1.0'dan itibaren) eklenmiştir. ViewModel yaşam döngüsüne bağlı, kullanıma hazır bir CoroutineScope sağlar.

kotlin
// Internal structure (simplified)
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 erişimde tembel (lazy) olarak oluşturulur ve setTag aracılığıyla önbelleğe alınır. SupervisorJob kullanır, bu da bir alt coroutine'deki istisnanın diğerlerini iptal etmediği anlamına gelir. Varsayılan dağıtıcı Dispatchers.Main.immediate'dir ve zaten Main üzerindeyse ek dağıtım olmadan ana iş parçacığında kod yürütür.

viewModelScope temizlik bildirimini nasıl alır

ViewModel yaşam döngüsünden çıktığında (Activity sonlandırılır veya Fragment kaldırılır), sistem clear() çağırır ve bu da onCleared()'ı tetikler. Bu geri çağrıda viewModelScope, Job'ını iptal eder ve tüm aktif coroutine'leri yinelemeli olarak sonlandırır. Mekanizma Closeable arayüzü aracılığıyla uygulanır; scope'un Job'ı otomatik kapatma için bir kaynak olarak kaydedilir.

viewModelScope nasıl çalışır: ViewModel yaşam döngüsüne bağlanma

viewModelScope'un ViewModel yaşam döngüsüne bağlanma mekanizması, etiketleme ve onCleared geri çağrısına dayanır. Adım adım inceleyelim.

Adım 1: İlk erişimde scope oluşturma

ViewModel viewModelScope.launch { ... } yürüttüğünde, getter JOB_KEY etiketi altında zaten bir scope depolanmış olup olmadığını kontrol eder. Scope yoksa yeni bir CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) örneği oluşturulur. Scope, dahili bir etiket haritası aracılığıyla ViewModel içinde depolanır.

Adım 2: Coroutine yaşam döngüsü

viewModelScope.launch veya viewModelScope.async aracılığıyla başlatılan tüm coroutine'ler, scope'un SupervisorJob'unun alt öğeleri haline gelir. Ana iş parçacığında çalışırlar (withContext aracılığıyla farklı bir dağıtıcı belirtilmedikçe). ViewModel canlı olduğu sürece coroutine'ler aktif, askıda veya tamamlanmış olabilir.

Adım 3: onCleared'da iptal

Sistem ViewModel'i yok ettiğinde, ViewModel.clear() çağrılır. clear() içinde aşağıdakiler olur:

  • Özel temizlik mantığı için onCleared() çağrılır
  • addCloseable aracılığıyla kaydedilen tüm Closeable kaynakları kapatılır
  • viewModelScope'un Job'ı Cancelled durumuna geçer
  • Tüm alt coroutine'ler yinelemeli olarak iptal edilir
  • Çöp toplayıcı için scope'a yapılan referanslar serbest bırakılır

Döndürmeye dayanıklılık

Ekran döndürüldüğünde Activity yeniden oluşturulur, ancak ViewModel hayatta kalır (ViewModelStoreOwner sayesinde). Bu, viewModelScope'un aktif kaldığı ve coroutine'lerin kesintisiz olarak yürütülmeye devam ettiği anlamına gelir. Activity yeniden oluşturulduktan sonra, aynı ViewModel (ve aynı scope) yeniden kullanılır — veri yükleme sıfırdan başlamaz.

MVVM mimarisinde viewModelScope

MVVM (Model-View-ViewModel), Google tarafından Android uygulamaları için önerilen mimaridir. viewModelScope, asenkron işlemlerin yürütücüsü olarak bu mimaride merkezi bir rol oynar.

Mimari katmanlarında viewModelScope'un rolü

KatmanBileşenviewModelScope'un rolü
UIActivity / FragmentViewModel'den StateFlow/LiveData'yı gözlemler
ViewModelViewModelviewModelScope aracılığıyla coroutine başlatır, UI durumunu yönetir
RepositoryRepositoryviewModelScope coroutine'lerinden çağrılan suspend işlevleri sağlar
DataDAO / ApiGerçek istekleri yürütür (Room, Retrofit)

ViewModel, viewModelScope aracılığıyla coroutine başlatır ve bunların içinde Repository'nin suspend işlevlerini çağırır. Sonuç StateFlow'a dönüştürülür ve UI katmanı tarafından gözlemlenir. Bu tasarım, net sorumluluk ayrımı ve her katmanın bağımsız test edilebilirliğini sağlar.

Neden ViewModel'de viewModelScope, Fragment'te değil

Coroutine'ler Fragment'ten başlatılsaydı, ekran döndürüldüğünde Fragment'in yok edilmesiyle iptal edilirlerdi. ViewModel döndürmeden sonra hayatta kalır, bu nedenle kendi scope'unda başlatılan coroutine'ler yürütülmeye devam eder. Veri yüklerken lifecycleScope'a kıyasla viewModelScope'un temel avantajı budur.

viewModelScope kullanım örnekleri

Kotlin ile bir Android uygulamasında viewModelScope kullanımının üç pratik senaryosunu inceleyelim.

Örnek 1: ViewModel oluşturulurken veri yükleme

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 bloğunda, profil yükleme hemen başlar. Coroutine varsayılan olarak ana iş parçacığında çalışır. Depo, suspend işlevi içindeki ağ isteği için withContext(Dispatchers.IO) kullanır, bu nedenle ViewModel iş parçacığı değiştirmeyle ilgilenmek zorunda kalmaz.

Örnek 2: sealed class ile hata yönetimi

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 durumu bir sealed class UiState aracılığıyla tanımlanır. ViewModel her değişiklikte durumu günceller. Fragment, StateFlow'a abone olur ve yalnızca mevcut duruma tepki verir, önceki döndürmelerden gelen eski çağrıları yok sayar.

Örnek 3: Yeni istekte önceki coroutine'i iptal etme

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

Her yeni arama sorgusunda, önceki coroutine iptal edilir. delay(300) debounce uygular — arama yalnızca 300 ms hareketsizlikten sonra yürütülür. Bu, sunucu yükünü azaltır ve güncel olmayan sonuçları önler.

viewModelScope vs lifecycleScope: ne zaman hangisi seçilmeli

Her iki scope da AndroidX Lifecycle kütüphanesi tarafından sağlanır, ancak farklı yaşam döngülerine bağlıdır. Seçim, görevin türüne bağlıdır.

Scope karşılaştırması

ÖzellikviewModelScopelifecycleScope
SahipViewModelLifecycleOwner (Activity/Fragment)
Döndürmede iptalHayır (ViewModel hayatta kalır)Evet (Activity yeniden oluşturulur)
Varsayılan dağıtıcıDispatchers.Main.immediateDispatchers.Main.immediate
KullanılabilirViewModelActivity, Fragment, Service
Tipik kullanımVeri yükleme, iş mantığıUI etkileşimleri, animasyonlar

Google önerileri

Google, tüm veri yükleme ve işleme görevleri için viewModelScope kullanılmasını önerir. lifecycleScope, UI yaşam döngüsünün belirli bir anına bağlı işlemler için kullanılmalıdır — örneğin, ekranın ilk görünümünde bir animasyon başlatmak veya ekrandan çıkıldığında durması gereken konum güncellemelerine abone olmak.

viewModelScope ile çalışırken yaygın hatalar

İyi belgelenmiş bir Android API'sinde bile geliştiriciler tipik hatalar yapar. En yaygın dört sorunu inceleyelim.

Hata 1: Scope iptalinden sonra UI'yi güncelleme

En sinsi hata, ViewModel temizlendikten sonra StateFlow veya LiveData'yı güncellemeye çalışmaktır. viewModelScope onCleared()'da iptal edilmesine rağmen, bir coroutine iptal yürürlüğe girmeden önce kod çalıştırabilir. Kontrol için isActive kullanın veya catch bloğunun tamamlanmasına güvenin.

Hata 2: SupervisorJob'u dikkate almadan coroutine başlatma

viewModelScope dahili olarak SupervisorJob kullanır ve bu, coroutine'ler arasındaki hataları yalıtır. Ancak, viewModelScope.launch içinde kendi Job()'u ile bir coroutine başlatırsanız, bu coroutine SupervisorJob'un alt öğesi olur ancak diğer coroutine'lerdeki hatalardan kaynaklanan iptale karşı korunmaz.

Hata 3: Tek bir scope'ta çok fazla coroutine

viewModelScope'un katı bir sınırı olmamasına rağmen, binlerce aktif coroutine sistemi yavaşlatabilir. Uzun veri listeleri için, her öğe için ayrı coroutine oluşturmak yerine Flow'u collectLatest ile kullanın.

Hata 4: viewModelScope yerine GlobalScope kullanma

viewModelScope yerine yanlışlıkla GlobalScope içe aktarılırsa, ViewModel temizlendiğinde coroutine iptal edilmez. Bu, bellek sızıntılarına ve potansiyel çökmelere yol açar. Özellikle Fragment alt sınıflarında, coroutine'lerin her zaman viewModelScope aracılığıyla başlatıldığından emin olun.

Sıkça Sorulan Sorular

viewModelScope'un varsayılan dağıtıcısını değiştirebilir miyim?

viewModelScope'un dağıtıcısını doğrudan değiştiremezsiniz — Dispatchers.Main.immediate olarak sabit kodlanmıştır. Ancak, bir coroutine içinde withContext aracılığıyla başka bir dağıtıcıya geçebilirsiniz. Testlerde dağıtıcıyı değiştirmek için bir Rule aracılığıyla TestDispatcher kullanın.

viewModelScope'u Repository'ye nasıl aktarırım?

Scope'u Repository'ye aktarmayın — bu mimari ilkeleri ihlal eder. Repository suspend işlevleri sağlamalıdır ve ViewModel'in kendisi viewModelScope aracılığıyla coroutine'leri yönetir. Repository bir scope gerektiriyorsa, mimariyi Clean Architecture lehine yeniden değerlendirin.

viewModelScope neden SupervisorJob kullanır?

SupervisorJob, bir coroutine'deki istisnanın (örneğin, birden çok bağımsız istekten birindeki yükleme hatası) diğer coroutine'leri iptal etmemesini sağlar. Bu, farklı ekranların bağımsız veri yüklediği ViewModel senaryosuyla uyumludur.

viewModelScope Jetpack Compose'da kullanılabilir mi?

Evet, viewModelScope UI türünden (View System veya Jetpack Compose) bağımsız olarak herhangi bir ViewModel'de kullanılabilir. Compose'da da coroutine'ler viewModelScope aracılığıyla başlatılırken, UI efektleri için LaunchedEffect ve rememberCoroutineScope kullanılır.

viewModelScope.cancel() çağrıldığında bir coroutine'e ne olur?

viewModelScope.cancel() çağırmak scope'u hemen iptal eder — tüm aktif coroutine'ler CancellationException ile sonlanır. Daha sonra viewModelScope.launch çağrılırsa, getter'a bir sonraki erişimde otomatik olarak yeni bir scope oluşturulur.

Özet

  • viewModelScope — ViewModel yaşam döngüsüne bağlı CoroutineScope, onCleared()'da otomatik iptal
  • SupervisorJob + Dispatchers.Main — hata yalıtımı ve güvenli UI erişimi sağlayan iç yapılandırma
  • Ekran döndürme — ViewModel hayatta kalır, bu nedenle viewModelScope'taki coroutine'ler yeniden başlatılmadan devam eder
  • MVVM mimarisi — viewModelScope, ViewModel katmanında asenkron işlemler için merkezi ögedir
  • lifecycleScope — ViewModel'e değil, Activity/Fragment yaşam döngüsüne bağlı işlemler için alternatif
  • StateFlow — sealed class aracılığıyla viewModelScope coroutine'lerinden UI'ya veri aktarmanın tercih edilen yolu
  • GlobalScope tehlikelidir — viewModelScope'u GlobalScope ile değiştirmek bellek sızıntılarına ve uygulama çökmelerine yol açar

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun