Coroutines ve Flow: Kotlin’deki Asenkron Programlama

 

Coroutines Nedir ve Avantajları Nelerdir?

Coroutines, Kotlin’in asenkron programlama için sunduğu hafif bir framework’tür. Coroutines, klasik thread’lere kıyasla daha az kaynak kullanarak eşzamanlı işlemleri kolayca yönetmeyi sağlar. Uzun süren işlemleri UI thread’i bloke etmeden gerçekleştirme yeteneği sunar ve uygulama performansını artırır.

 

Coroutines’in Avantajları:

  • Hafif Yapı: Coroutines, thread’den çok daha hafiftir ve bir thread üzerinde binlerce coroutine çalıştırılabilir.

  • Basit Kodlama Stili: Asenkron işlemleri senkron görünülü bir şekilde yazmayı sağlar.

  • Suspend Fonksiyonları ile Entegrasyon: Uzun süren işlemler için suspend fonksiyonlar kullanarak kolayca asenkron işlemler gerçekleştirilir.

  • Error Handling: CoroutineScope ve SupervisorJob kullanarak hata yönetimini daha kontrol edilebilir hale getirir.

  • Lifecycle Uyumluluğu: Android’de LifecycleScope ve ViewModelScope gibi yapılandırmalarla çalışr.

 


 

Coroutine Scope Nedir?

Scope, Coroutine’lerin çalıştığı alan veya kapsama denir. Scope, Coroutine’lerin ne zaman başlatılacağı, çalıştırılacağı ve iptal edileceği gibi işlemleri kontrol eder. Coroutine’leri doğru bir şekilde yönetmek için uygun scope seçimi çok önemlidir.

Farklı Coroutine Scope Çeşitleri

  1. GlobalScope

    • Tanım: Tüm uygulama genelinde bir alan sağlar. GlobalScope ile başlatılan coroutine, uygulama hayatta olduğu sürece çalışr ve manuel olarak iptal edilmesi gerekir.

    • Kullanım Alanı: Uzun süreli çalışan işlemler için uygundur, ancak dikkatli kullanılmalıdır. Genellikle hata yönetimi zor olduğu için önerilmez.

    GlobalScope.launch {
        // Uzun süren bir işlem
    }
  2. ViewModelScope

    • Tanım: Her ViewModel için özel olarak tanımlanmış bir scope’tur. ViewModelScope’da başlatılan coroutine, ViewModel’in yaşam döngüsü ile sınırlıdır ve ViewModel yok edildiğinde otomatik olarak iptal edilir.

    • Kullanım Alanı: ViewModel’den veri alma ve işleme işlemleri.

    class MyViewModel : ViewModel() {
        fun fetchData() {
            viewModelScope.launch {
                // Veri işleme işlemleri
            }
        }
    }
  3. LifecycleScope

    • Tanım: Her lifecycle (Activity veya Fragment) için bir scope tanımlanır. LifecycleScope’da başlatılan coroutine, ilgili lifecycle sona erdiğinde otomatik olarak iptal edilir.

    • Kullanım Alanı: UI ile ilişkili işlemler (animasyonlar veya UI güncellemeleri).

    lifecycleScope.launch {
        // UI işlemleri
    }
  4. CoroutineScope

    • Tanım: Kendi özel scope’umuzu oluşturmayı sağlar. GlobalScope’a benzer, ancak daha özelleştirilebilir. Belirli bir thread veya dispatcher seçerek işlemleri yönetebilirsiniz.

    • Kullanım Alanı: Daha spesifik thread seçimleri ve manuel coroutine yönetimi gerektiren durumlar.

    val myScope = CoroutineScope(Dispatchers.IO)
    myScope.launch {
        // IO işlemleri
    }
  5. CoroutineScope (Fonksiyon Olarak Kullanımı)

    • Tanım: Bir coroutineScope, yalnızca bir suspend fonksiyon içinde veya başka bir scope’un (runBlocking gibi) içinde çalıştırılabilir. Bu, coroutine’nin kapsama alanını kontrol etmek ve güvenli bir şekilde çalıştırmak için kullanılır.

    • Kullanım Alanı: Suspend fonksiyonlar içinde coroutine işlemlerini bölmek ve organize etmek.

    suspend fun performTask() = coroutineScope {
        launch {
            // Alt görev 1
        }
        launch {
            // Alt görev 2
        }
    }

NOT: coroutineScope, bir GlobalScope, runBlocking veya başka bir coroutine scope olmadan doğrudan kullanılamaz. Aksi takdirde derleme hatası alırsınız.

 


 

 

Kotlin Flows

 

 

Flow, Kotlin Coroutines ile birlikte çalışan reaktif bir veri akışı modelidir. Akış (flow), veri üreticiden tüketiciye sürekli veri gönderimini sağlar. Özellikle, Flow, zaman uyumsuz bir şekilde sıralı veri yayınlamak için kullanılır.

 

Flow’un Temel Özellikleri

  • Cold Nature (Soğuk Akış): Flow, yalnızca bir tüketici (collector) abone olduğunda veri üretmeye başlar.

  • Unidirectional Data Stream (Tek Yönlü Veri Akışı): Veriler, üreticiden tüketiciye doğru akar ve tersine bir veri akışı olmaz.

  • Cancellation Support (İptal Desteği): CoroutineScope ile entegre olduğu için iptal edilebilir.

  • Suspend Fonksiyonlarla Entegrasyon: Veri akışı içerisinde suspend fonksiyonlar kolayca kullanılabilir.

 


 

Flow Çeşitleri

Flow yapısı, cold flow ve hot flow olmak üzere iki ana kategoriye ayrılır.

1. Cold Flow

  • Tanım: Abone olmadan (collect çağrılmadan) veri üretmez.

  • Özellikler:

    • Her abone, Flow’un başından itibaren veri alır.

    • Her abone için veri üretimi yeniden başlar.

  • Kullanım Alanı: Veritabanı sorguları, API çağrıları gibi işlemler için uygundur.

    fun fetchItems(): Flow<String> = flow {
        emit("Item 1")
        delay(1000)
        emit("Item 2")
    }

2. Hot Flow

  • Tanım: Abonelikten bağımsız olarak sürekli veri üretir.

  • Türleri:

    • StateFlow

    • SharedFlow

a. StateFlow
  • Tanım: Son durumu (state) tutan ve abonelik sırasında bu durumu sağlayan bir hot flow türüdür.

  • Özellikler:

    • Her zaman bir başlangıç değeri ile başlatılır.

    • Son değeri depolar ve yeni abonelere iletir.

    • Yalnızca değer değiştiğinde güncellemeler yayınlanır.

  • Kullanım Alanı: UI state yönetimi.

    private val _uiState = MutableStateFlow("Initial State")
    val uiState: StateFlow<String> = _uiState
    
    fun updateState(newState: String) {
        _uiState.value = newState
    }
b. SharedFlow
  • Tanım: Birden fazla abonelik için yapılandırılabilir bir hot flow türüdür. Replay cache ile eski değerleri birden çok aboneye sağlayabilir.

  • Özellikler:

    • Başlangıç değeri zorunlu değildir.

    • Replay özelliği ile geçmişte yayınlanan belirli bir sayıda değeri saklar.

    • Çok sayıda abonelik için tasarlanmıştır.

  • Kullanım Alanı: Event-based yapıların (Toast veya Snackbar mesajları) yönetimi.

    private val _events = MutableSharedFlow<String>(replay = 1)
    val events: SharedFlow<String> = _events
    
    suspend fun emitEvent(event: String) {
        _events.emit(event)
    }

 


 

Cold Flow ve Hot Flow Arasındaki Farklar

Özellik Cold Flow Hot Flow
Başlangıç Değeri Zorunlu değil StateFlow için zorunlu, SharedFlow opsiyonel
Veri Üretimi Abonelik sonrası başlar Sürekli olarak veri üretir
Depolama Veri tutmaz StateFlow son değeri, SharedFlow replay değerlerini tutar
Abone Durumu Her abone baştan başlar Mevcut durumdan devam eder
 

 


 

StateFlow ve SharedFlow Arasındaki Farklar

Özellik StateFlow SharedFlow
Başlangıç Değeri Zorunlu Opsiyonel
Replay Son değeri saklar Birden fazla değeri saklayabilir
Güncellemeler Sadece farklı değerlerde yayın yapar Her yayın çağrısını iletir
Kullanım Alanı UI State yönetimi Event bazlı veri yönetimi

 


 

Flow ve LiveData Arasındaki Farklar

Özellik Flow LiveData
Lifecycle Aware Hayır Evet
Platform Genel amaçlı Android UI bileşenleri için
Kullanım Alanı Daha geniş kapsamlı reaktif işlemler UI güncellemeleri

Flow, özellikle daha karmaşık asenkron işlemler ve veri akışları için tercih edilirken, LiveData yaşam döngüsüne duyarlı olması sayesinde UI bileşenleri için uygundur.