CoroutineScope, bir coroutine'in yaşam döngüsünü tanımlayan ve yeni coroutine'ler başlatmak için bağlam sağlayan bir Kotlin arayüzüdür. Kotlin belgelerine, 2025 göre, her CoroutineScope örneği bir CoroutineContext içerir ve içinde başlatılan tüm coroutine'leri yönetir. Scope iptal edildiğinde (cancel), tüm alt coroutine'ler otomatik olarak iptal edilir ve bellek sızıntıları önlenir.
Önemli noktalar
CoroutineScope, kotlinx.coroutines kütüphanesinden coroutine'ler için bir kapsayıcı görevi gören temel bir arayüzdür. Coroutine yaşam döngüsünün sınırlarını tanımlar: scope tamamlandığında, içindeki tüm coroutine'ler otomatik olarak iptal edilir.
public interface CoroutineScope {
public val coroutineContext: CoroutineContext
}
Arayüz yalnızca bir alan içerir — coroutineContext. Scope, bu alan aracılığıyla içinde başlatılan tüm coroutine'lere bir dağıtıcı (Dispatcher), bir iş (Job), bir istisna işleyici ve diğer bağlam öğelerini sağlar.
Tüm coroutine başlatma işlevleri — launch, async, runBlocking — CoroutineScope üzerindeki genişletme işlevleridir. Bu, yalnızca bir scope nesnesi mevcut olduğunda çağrılabilecekleri anlamına gelir. Bu tasarım, her coroutine'in açıkça tanımlanmış bir üst öğeye ve yaşam döngüsüne sahip olmasını sağlar.
Android'de, her mimari bileşenin kendi scope'u vardır: ViewModel için viewModelScope, Activity/Fragment için lifecycleScope. Sunucu uygulamalarında, scope bir HTTP isteğine veya veritabanı bağlantı havuzuna bağlanabilir.
CoroutineScope'un iç çalışmasını anlamak, Job kavramına ve yapısal eşzamanlılık ilkesine aşinalık gerektirir.
Her coroutine başlatıldığında bir Job nesnesi (veya async için Deferred) döndürür. Job, sınırlı bir yaşam döngüsüne sahip bir görevi temsil eder: New, Active, Completing, Completed, Cancelling, Cancelled. Job nesneleri bir ağaç yapısı oluşturur:
Yapısal eşzamanlılık, Kotlin Coroutines'in temel bir mimari ilkesidir ve coroutine'in yaşam döngüsünün scope'unun yaşam döngüsüne bağlı olduğu anlamına gelir. Bu, coroutine'in scope tamamlandıktan sonra da yaşamaya devam ettiği “ateşle ve unut” modelinin tersidir. Yapısal eşzamanlılığın avantajları:
scope.cancel() çağrıldığında, scope'un Job'ı Cancelled durumuna geçer ve bu, tüm alt Job'ları yinelemeli olarak iptal eder. İptalden sonra, scope yalnızca yeni bir CoroutineScope örneği oluşturularak yeniden kullanılabilir.
CoroutineScope'u bir fabrika işlevi aracılığıyla veya sınıfınızda arayüzü uygulayarak oluşturabilirsiniz. Her iki yaklaşımı da inceleyelim.
val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
scope.launch {
println("Running on ${Thread.currentThread().name}")
}
Fabrika işlevi bir CoroutineContext alır ve belirtilen bağlamla bir scope oluşturur. Örnek, CPU yoğun görevler için Dispatchers.Default ve alt coroutine'ler arasındaki istisnaları yalıtan SupervisorJob'ı kullanır.
class MyRepository {
private val scope = CoroutineScope(Dispatchers.IO + Job())
suspend fun fetchData(): Data = scope.async {
api.getData()
}.await()
fun cleanup() {
scope.cancel()
}
}
Scope'u bir sınıf alanı olarak saklar ve iptal etmek için manuel olarak cleanup çağırırız. Bu yaklaşım, yönetilen yaşam döngüsüne sahip bileşenler — örneğin, depo veya yöneticiler — için uygundur.
Kotlin, by anahtar sözcüğü aracılığıyla CoroutineScope uygulamasını devretmeye izin verir:
class DataLoader : CoroutineScope by CoroutineScope(Dispatchers.IO) {
fun load() {
launch {
// coroutine runs in DataLoader scope
}
}
}
Bu yaklaşım, sınıfın kendisi bir scope olduğunda ve coroutine başlatma yöntemleri sağlamak istediğinde kullanışlıdır. Ancak dikkatli olun: sınıf, CoroutineScope'un tüm yöntemlerini (cancel dahil) devralır ve bu da kapsüllemeyi bozabilir.
GlobalScope, tüm uygulama için bir tekil CoroutineScope'tur. Üretim kodunda kullanımı resmi olarak önerilmez.
JetBrains, GlobalScope'a yalnızca nadir senaryolarda izin verir: tüm Activity'ler kapatıldıktan sonra bile yaşaması gereken uygulama düzeyindeki arka plan işlemleri (örneğin, veri senkronizasyonu, analitik). Ancak bu durumlarda bile, CoroutineScope(SupervisorJob()) ile kendi scope'unuzu oluşturmanız tercih edilir.
Açık yaşam döngüsü yönetimi ile her zaman özel bir CoroutineScope kullanın. Android'de bunlar viewModelScope ve lifecycleScope'tur. Sunucu uygulamalarında, her istek veya bağlantı havuzu için bir scope oluşturun.
Her iki işlev de paralel görevler için geçici bir scope oluşturan askıya alma işlevleridir, ancak istisnalar karşısındaki davranışları temelde farklıdır.
| Özellik | coroutineScope | supervisorScope |
|---|---|---|
| Hata durumunda davranış | Alt coroutine'deki istisna diğerlerini iptal eder | Alt coroutine'deki istisna diğerlerini iptal etmez |
| Hata yayılımı | Evet, ilk istisna dışarıya yayılır | Evet, ilk istisna dışarıya yayılır |
| Varsayılan Job | Job() — alt öğeler üst öğeye bağlı | SupervisorJob() — alt öğeler birbirine bağlı değil |
| Tipik kullanım durumu | Çok adımlı atomik işlem | Bağımsız paralel görevler (UI yüklemeleri) |
Birden çok paralel işlem tek bir atomik işlem oluşturduğunda coroutineScope kullanın. Örneğin, üç sunucudan veri yükleme: bir istek başarısız olursa, diğerleri anlamsızdır.
suspend fun loadProductPage(): ProductPage = coroutineScope {
val product = async { api.getProduct() }
val reviews = async { api.getReviews() }
ProductPage(product.await(), reviews.await())
}
getProduct veya getReviews bir istisna fırlatırsa — her iki coroutine de iptal edilir ve istisna çağıran koda yayılır.
Paralel işlemler birbirine bağlı olmadığında supervisorScope kullanın. Örneğin, birden çok bağımsız bölümde profil verilerini yükleme: öneriler bölümü başarısız olursa, profil başlığı ve arkadaş listesi görüntülenmelidir.
Kotlin'de CoroutineScope kullanırken geliştiricilerin en yaygın hatalarına bakalım.
En yaygın coroutine sızıntısı senaryosu, bileşen sona erdiğinde cancel çağırmadan scope oluşturmaktır. Scope iptal edilmezse, coroutine'ler çalışmaya devam eder ve nesnelere referansları tutar. Android'de, otomatik olarak iptal edilen viewModelScope veya lifecycleScope kullanın.
GlobalScope, Android bileşen yaşam döngüsünü yok sayar. Bir Activity kapatıldıktan sonra GlobalScope'ta başlatılan bir coroutine çalışmaya devam eder ve UI'yi güncellemeye çalışır — bu da çökmeye neden olur. UI bileşenleri için her zaman lifecycleScope kullanın.
cancel() çağrıldıktan sonra scope yeniden kullanılamaz — içindeki tüm coroutine'ler zaten tamamlanmıştır. Fabrika işlevi aracılığıyla yeni bir CoroutineScope örneği oluşturun. Job() yeniden etkinleştirmeyi desteklemez.
by ile devredildiğinde, sınıf her yerden çağrılabilen genel bir cancel() yöntemi alır ve kapsüllemeyi bozar. Arayüzü devretmek yerine scope'u özel bir alan olarak saklayın.
Sık sorulan sorular
CoroutineScope, bir CoroutineContext'e sahip olan ve coroutine'lerin yaşam döngüsünden sorumlu olan bir arayüzdür. CoroutineContext, bir coroutine'in “nasıl” yürütüleceğini tanımlayan öğeler (dağıtıcı, job, hata işleyici) kümesidir. Bir fark: scope coroutine'leri oluştururken, bağlam onların davranışını kontrol eder.
Evet, bu standart bir kalıptır: CoroutineScope(Dispatchers.IO + SupervisorJob()). SupervisorJob, alt coroutine'lerden biri bir istisna fırlattığında diğerlerinin zincirleme iptalini önler. Bu, birindeki hatanın diğerlerini durdurmaması gereken bağımsız paralel görevler için kullanışlıdır.
Bir scope'taki coroutine sayısında sınır yoktur — yalnızca kullanılabilir bellek ve dağıtıcı ayarlarıyla sınırlıdırlar. Pratik sınır genellikle tek bir scope'ta binlerce etkin coroutine'dir. Ancak, çok sayıda coroutine mimari sorunlara işaret edebilir.
Doğru yol, scope'u kurucu aracılığıyla sınıfa geçirmek veya kotlinx-coroutines-test'ten runBlockingTest / runTest kullanmaktır. Testlerde, scope'u TestCoroutineDispatcher ile değiştirebilir ve coroutine yürütmesini manuel olarak kontrol edebilirsiniz.
Hayır, scope bir coroutine için harici bir kapsayıcıdır. Coroutine'in kendisi bir scope değildir. Ancak, bir coroutine içinde coroutineScope veya supervisorScope aracılığıyla alt coroutine'leri paralel olarak başlatmak için yeni bir scope oluşturabilirsiniz.
Özet
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.
Ayrıca okuyun