Coroutines Nedir?
Selamlar 👋, sizlere bu yazımda Coroutine’ler hakkında bilgi vermeye çalışacağım. O zaman başlayalım.
Kullanıcı arabiriminin bloklanmadan ya da donmadan çalışmasını, ağır görevlerin arka planda gerçekleşmesini sağlayabilmekteyiz. Peki bunu nasıl yapabiliriz? 👇
🔸Coroutines Nedir?
- Co ve Routines’in birleşimden meydana gelmektedir. Co, işbirliği anlamında, Routines ise fonksiyonlar anlamındadır.
- Coroutine, Main Thread’i bloklayabilecek, uygulamaların yanıt vermemesine neden olabilecek uzun süreli işlemlerin(mesela internetten veri çekme gibi) arka planda asenkron olarak yürütülmesine imkan tanır. Coroutine’ler, thread’lere benzer. Ancak thread değildir. Thread tarafından yürütülen görev parçalarıdır.
- Coroutine’ler, thread içinde yürütülürler. Bir thread içerisinde birden çok Coroutine yürütülebilmektedir.
- Coroutine’ler askıya(suspandable) alınabilirler. Bu sayede istersek Coroutine’i durdurabilir ya da tekrardan kaldığı yerden devam etmesini sağlayabiliriz.
- Context’ni kolayca değiştirebilir ve bu sayede başka thread’ler arasında geçiş yapabiliriz.
🔸 Coroutine’nin Özellikleri
- Lightweight: Bir thread üzerindebirden çok Coroutine çalıştırılabilir ve Coroutine’ler üzerinde çalıştığı thread’i bloklamaz. Bu özelliği sayesinde birden çok eş zamanlı işlemi destekleyerek bellekten tasarruf sağlamaktadır.
- Fewer Memory Leaks: Coroutine’ler structured concurrency(yapılandırılmış eşzamanlılık) ilkesini izler. Bunun anlamı ise Coroutine’lerin belirli bir CoroutineScope içerisinde başlatılmasıdır.
- Built-in Cancellation Support
- Jetpack Integration: Birçok Jetpack kütüphanesi Coroutine desteği sağlayan extension’lar içerir.
🔸 Scope
- Scope, Coroutine’lerin çalıştığı alan/kapsam olarak düşünülebilir.
Şimdi sırayla farklı Scope çeşitlerine bakalım.
- GlobalScope: Coroutine için tüm uygulama içerisinde bir alan oluşturuyor. uygulama hayatta olduğu sürece GlobalScope’da hayatta kalıyor.
2. ViewModelScope: Uygulamadaki her ViewModel için bir ViewModelScope tanımlanır. ViewModel iptal edilirse coroutine’de iptal edilir.
3. LifecycleScope: Her bir lifecycle nesnesi için bir lifecycleScope nesnesi tanımlanır. lifecycleScope yok edildiğinde oluşturulan coroutine’de iptal edilir.
4. CoroutineScope: Kendi özel scope’muzu oluşturmayı sağlar. GlobalScope’a benzer. Ancak CoroutineScope’da spesifik olarak bir thread seçip işlemlerimizi orada yapabilmemize imkan tanır.
NOT: Bir de coroutineScope bulunmaktadır. Bu scope ya suspend fonksiyon içerisinde ya da runBlocking, GlobalScope gibi bir scope’un içerisinde yazılmalıdır. Yazılmadığı taktirde hata vermektedir.
🔸 Coroutine Builder
- launch:
- Coroutine başlatma fonksiyonudur.
- İçinde bulunduğu thread’i bloklamaz.
- Arka planda işletilecek operasyonlarda kullanılır.
- Bir Job nesnesi döndürür. Bu Job nesnesini iptal edersek Coroutine’de iptal etmiş oluruz. Job’ı istediğimiz gibi kontrol edebiliriz.(cancel işlemi, işlem tamamlandıktan sonra yapılacak işlemler,..)
- Arka planda nasıl tutulduğuna bakacak olursak:
- Extension function olarak tutulmaktadır.
NOT:
Job -> Coroutine’nin yaşam döngüsünü kontrol etmektedir. Job nesnesini cancel ederek Coroutine’i bitirebiliriz. cancel() gibi farklı fonksiyonları bulunmaktadır.
2. async:
- Coroutine başlatma fonksiyonudur.
- Bulunduğu thread’i bloklamaz.
- Launch’dan farklı olarak Job yerine Deferred<T> döndürür.
- Sonucu await() fonksiyonu ile alırız. await() fonksiyonu suspend bir fonksiyondur.
Hem await’in hem de async’nin arka planda nasıl tutulduklarına bakalım.
- async, Extension funciton olarak tutulmaktadır.
NOT: Extension function’ları bilmiyorsanız eğer daha önceden bu konu ile ilgili yazdığım yazıya bakabilirsiniz.
👉 https://tugce-aras.medium.com/extension-functions-3a2fd7fbb4d8
3.runBlocking:
- Coroutine’lerin işleri bitene kadar mevcut thread’in bloke edilmesini sğlar.
- runBlocking kullanımı çok önerilmez. Daha çok test hazırlarken kullanılır.
🔸 Suspend Function
- Suspend funciton’lar mevcut tread’i bloke etmeden coroutine’nin yürütülmesini askıya alır.
- Ya bir coroutine içerisinden ya da başka bir Suspend function içerisinden çağrılırlar.
- Suspend fonksiyonlar durdurulabilir ya da yeniden başlatılabilirler.
- Suspend fonksiyonlar normal fonksiyonları çağırabilirken, normal fonksiyonlar suspend bir fonksiyonu çağıramazlar.
Yazımına bakacak olursak:
NOT: İç içe coroutine’ler yazabilmekteyiz.
🔸 Dispatcher
- Coroutine’leri farklı thread’lerde çalıştırabilmemizi sağlar. Yani context switch işlemi yapar.
- Yapılacak işleme göre dispatcher vasıtasıyla hangi thread’de gerçekleştirmek istediğimizi söyleriz.
- Farklı dispatcher türleri bulunmaktadır. Bunlar:
- Dispatcher.Default: CPU ile alakalı işlemlerde kullanlır. Örneğin; büyük listeleri sıralama, Parsing JSON,.. gibi
- Dispatcher.IO: I/O işlemlerinde kullanılır. Örneğin; networking işlemleri, dosya okuma-yazma işlemleri, veri tabanındaan veri çekme işlemleri,..
- Dispatcher.Main: UI ile ilgili işlemleri içermektedir. Örneğin görünümleri güncelleme, RecyclerView’deki listeleri gösterme,..
- Dispatcher.Unconfined: Çağrıldığı thread’de coroutine başlatır. Herhangi bir thread ile sınırlı değildir.
🔸 withContext
- Coroutine Dispatcher içerisinde yapılan işlere göre hangi dispatcher‘a geçmek istiyorsak withContext ile geçiş yapabilmekteyiz.
- Aynı scope içinde farklı thread’lerde işlem yapılmasına imkan tanır.
🔸 Coroutine Exception Handling
- Herhangi bir hata olması durumunda o hatayı yakalamak adına kullanılan bir yapıdır. Örneğin Retrofit ile kullanıldığı zaman hata olması durumunda, o hatayı yakalamak için kullanılır.
Şu şekilde de kullanım yapılabilir:
Peki aşağıdaki gibi bir kullanım olursa:
“This is executed” yazısını çıktı olarak göremeyiz. Ama neden? 🤔
Çünkü, scope içerisinde birden fazla launch olsa dahi herhangi bir tanesi hata verdiği anda geri kalan kısımlar çalışmaz. Coroutine otomatik olarak iptal eder. Peki bu durumun önüne nasıl geçebiliriz? 👇
🔸 supervisorScope
- Gözlemleyici bir scope’tur.
- Scope içerisinde birden fazla launch olsa da hatta içlerinden bir tanesi hata verse dahi diğer kısımların çalışmasına olanak sağlayan bir yapıdır.
Kaynak
- https://developer.android.com/topic/libraries/architecture/coroutines
- https://developer.android.com/kotlin/coroutines
- https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html
- https://medium.com/androiddevelopers/coroutines-on-android-part-i-getting-the-background-3e0e54d20bb
- https://medium.com/gradeup/introduction-to-kotlin-coroutines-for-beginners-8b1d2a41c008
- https://medium.com/swlh/kotlin-coroutines-getting-started-in-android-f00d57e0a0a9
- https://medium.com/xebia-engineering/coroutines-in-android-d94b54caec55
- https://medium.com/trendyol-tech/kotlin-coroutine-asenkron-ve-paralel-programlama-c5a0b9e945c8
- https://medium.com/ekmob-developer-studio/nedir-bu-kotlin-coroutines-c51236856b28
- https://www.mobiler.dev/post/kotlin-coroutines-in-genel-tanitimi-ve-kullanimi
- https://amitshekhar.me/blog/kotlin-coroutines
- https://medium.com/androiddevelopers/coroutines-first-things-first-e6187bf3bb21