Kompleks Network Çağırımlarını Kotlin Coroutine’ler ile yönetmek + Retrofit 2
Android uygulama geliştirirken senkron/asenkron yani zincirleme veya paralel olarak atmamız gereken requestler illaki oluyor. Tabii ki bunu başarabilmek için aklınıza ilk gelen “RxJava”..
Fakat RxJava öğrenmek benim için şu aşamada pek kolay değil. Bu sebeple bende bu konuda başka nasıl bir çözüm olabilir diye ararken Kotlin Coroutine’ler ile gayet basit bir şekilde Senkron/Asenkron network requestleri atabileceğimi öğrendim ve sizlerle paylaşmak istedim. En azından RxJava, RxKotlin gibi frameworkleri kullananlar içinde farklı bir fikir vermiş olur.
Kotlin Coroutine’lere kısa bir giriş
Coroutine’ler RxJava gibi kendini henüz kanıtlamış değiller. KotlinConf 2018'de Coroutine’lerin artık deneysel olmadığı, güvenli bir şekilde kullanabileceğimiz dile getirildi. Coroutine’ler temel olarak Asenkron veya threadleri kilitlemeden programlama yapma imkanı sunan yapıdır. RxJava gibi bir framework yerine Kotlin içerisinde bulunan coroutine’leri kullanmak daha doğal bir çözüm olacaktır.
“Coroutineler threadlerin engellenmesini önlemek ve threadleri yeniden yapılandırmak için daha ucuz, daha kontrol edilebilir bir yapı sağlarlar.”
Coroutineleri projenize nasıl eklersiniz?
Coroutine’leri projeye eklemek oldukça basit.Öncelikle build.gradle
dosyasına dependency’i eklemeniz gerekiyor.
Coroutine’lere giriş
Coroutine’ler hafif yüklü thread’lerdir. JetBrains çalışanları normal Kotlin fonksiyonlarının önlerine suspend
kelimesi getirerek onların birer hafif yüklü, askıya alınmış fonksiyonlar haline gelmelerini sağladılar. Biraz daha açıklamak gerekirse;
suspend
fonksiyonlar normal fonksiyonlar gibi parametre alabilir veya bir dönüş değeri olabilir. Ancak sadece Coroutine’ler veya diğersuspend
fonksiyonlar tarafından çağrılabilir.
Sonuç olarak coroutine’ler bizim asenkron programlama yapmamızı daha iyi hale getirmek adına oluşturuldular.
İsterseniz ufak bir örnek ile başlayalım. Bildiğiniz üzere bir UI thread’i 5 saniyeden fazla cevap vermez ise Android Not Responding(ANR) hatasına yakalanır ve uygulama crash olur. Gelin coroutine ile UI üzerinde 10 saniye süren bir işlem yapalım ve sonra neler oluyor bir bakalım..
Şöyle bir kod yazdığımızda uygulama normal olarak açılıyor, hangi activity ayağa kalkıyor ise ilgili .xml de ayağa kalkıyor ve 10 saniye bekledikten sonra görüntü alt taraftaki gibi oluyor. UI Threadi üzerinde 10 saniye süren bir işlem olmasına rağmen ANR yaşanmadı ve uygulama kendi lifecycle’ında devam ediyor.
Launch ve Async
launch
ve async
Coroutine’de sıklıkla kullanılan iki fonksiyondur.
launch : Geçerli olan threadi bloklamadan yeni bir coroutine başlatır ve coroutine’e Job türünde bir geri dönüş değeri sağlar. Job iptal edilene kadar coroutine işini yapmaya devam eder. Ayrıca geçerli threadi durdurmak isterseniz
runBlocking
yapılandırıcısını kullanabilirsiniz.async : Yeni bir coroutine başlatır ve coroutine’e Deferred türünde bir geri dönüş değeri sağlar.
Deferred
iptal edilene kadar coroutine işini yapmaya devam eder.
Dispatchers.Main
bu coroutine’e ait bir yapılandırıcı veya fonksiyon değil ancak kısaca açıklamak gerekirse ; launch
veya async
içerisinde UI threadi ile alakalı bir güncelleme yapılacağı zaman bunu Android sistemine haber veren yapıdır diyebiliriz.
Retrofit ile birlikte nasıl kullanılır?
Öncelikle Retrofiti,Gson ve Retrofit’in coroutine ile birlikte sorunsuz çalışmasını sağlamak adına Jake Wharton tarafından yazılan Kotlin Coroutine Adapter adlı kütüphaneyi dependency olarak ekleyelim.
Tabii ki internet izni vermeyi de unutmayalım!
Interface tanımlama
Hızlı bir örnek yapmak adına JsonPlaceHolder adresinden 5000 image linki ve 100 tane de post içeriği alıp recyclerview a bastıralım. Öncelikle şu şekilde bir interface tanımlayalım.
Normal Retrofit interface’inden tek farkı artık Call<T> yerine Deferred<T> şeklinde tanımlama yapıyor olmamız.
Temel Retrofit Object’i oluşturma
Build.gradle
’a daha önceden eklediğimiz CoroutineAdapter
’ı artık kullanabiliriz.
.addCallAdapterFactory
diyerek RetrofitService ekleyelim.
Hepsini birleştirme vakti
GlobalScope içerisinde birbirinden bağımsız iki request atıp bunları ilgili adapterlara verebildik. Elbette bu kodun daha temiz yazılacağından eminim, en azından if-else kısımları temizlenebilir diye düşünüyorum. Düzenleme olarak öneriniz varsa yorumlarda belirtirseniz sevinirim.
Sonuç
RxJava, RxKotlin gibi Frameworkler kullanmadan Network işlemleri için basit bir şekilde Coroutine’ler ile requestlerimizi senkron/asenkron atabileceğimizi görmüş olduk.
Vakit ayırıp okuduğunuz için teşekkürler, umarım faydalı bir yazı olmuştur.
Dilerseniz projenin kodlarına buradan erişebilirsiniz.
Bu yazıyı hazırlarken yararlandığım kaynaklar :