Android LiveData- Flow
Herkese Selamlar, Bugün Android LiveData hakkında biraz konuşup, MVVM içerisinde Repository tarafında Flow ile devam edeceğiz. Umarım faydalı bir yazı olur. Hazırsanız hadi başlayalım.
Architecture Components den olan LiveData’ya geçmeden önce, Observer Design Patern hakkında konuşalım.
Observer (Gözlemci) Design Pattern
Observer Design Pattern ile, bir yapıdaki değişiklikle beraber farklı yapıların bu değişiklikten haberdar olup, değerlerinde veya işlemlerinde değişikliğe gitmesidir.
Şöyle bir örnek verelim. Mahallemizin Ayşe ablası camdan tüm mahalleyi gözetliyor. Mahalle hakkında en ufak gelişmeyi herkese yaymaya başlıyor.:)
LiveData Nedir?
LiveData Android Jetpack öğesidir. Observe(gözlemci) ve Observable(gözlemlenen) diye temelde 2 farklı yapısı mevcuttur. LiveData sayesinde projelerimizde, bir fonksiyonda veya değişkende oluşabilecek değişimi gözlemleyip bu değişimden etkilenmesini istediğimiz yapıları observe ettiğimiz yerden tetikleriz. LiveData ise bizlere bu değişikliği bildiriyor. Kardeşim senin bu gözlemlediğin X yok mu, bu çok değişti haberin olsun. Ona göre ne yapacaksan yap!.:). Her zaman güncel verileri tutar. UI ile ViewModel arasında haberleşmeyi sağlar.
Aslında biraz daha irdelemek istersek, SOLID programlamanın Single Responsibility Principle maddesi bizleri bir Mimari yapıyı kullanmaya teşvik eder. Çünkü bu madde bir sınıfın veya fonksiyonun yapması gereken yalnızca bir işi olması gerektiğini savunur. Bu noktada MVVM,MVP,MVC gibi çeşitli Yazılım Mimarileri kullanılır.
Yazılım mimarilerini kullanmaya başlayınca, başlıca sorunların ortaya çıktığını gözlemleriz. Oluşan sorunlara çözüm olarak ise Dependency Injection, LiveData, ViewModel gibi çeşitli yapılar geliştirilmiştir.
MVVM yazılım mimarisinde UI içerisinde Business Logic(BL) yer almamalıdır. Bizler de BL tanımlamalarını ViewModel içerisinde gerçekleştiririz. Fakat UI ile ViewModel arasında haberleşmenin ve değişikliklerin yakalanması için bir yapıya ihtiyacımız var bu noktada LiveData ihtiyacımızı karşılıyor.
Şöyle bir işlem düşünelim, geliştirdiğimiz projede uzak sunucu işlemlerini asenkron olarak gerçekleştiriyoruz. Peki biz işlemlerimize devam ederken, uzak sunucudan gelen datalardan nasıl haberdar olup, bu datalar üzerinden işlem gerçekleştireceğiz? işte bu noktada LiveData “Biz Sana Haber Veririz” diyor.
Memory Leak yoktur, bağlı olduğu UI lifecycle sonlandığında memory den silinir. Single Activity prensibini kullanıyorsanız, owner tanımlamasına dikkat etmeniz gerekmektedir. Farklı fragmenet’lar üzerinde işlem yaparken bile kullanmayacağınız LiveData’lar Memory’de kalmaya devam edecektir.
LiveData’lar bağlı oldukları UI’ların yaşam döngüleri sonlanmadıkça çalışmaya devam ederler. Örnek olarak uygulamamızı arka plana aldık onStop da bekliyoruz. Fakat LiveData işlemlerini yapmaya devam ediyor. İsterseniz ufak bir sayaç örneği üzerinden inceleyelim.
Öncesinde ViewModel ile ilgili yazdığım yazıyı inceleyebilirsiniz.
Build.Gradle(app)
// LiveData
def liveData = '2.2.0'
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$liveData"
ViewModel
MutableLiveData ve LiveData tipinde 2 farklı değişkeni, dışarıdan LiveData değişkenine müdahalede bulunulamaması için tanımladık. Sadece gözlemlenebilir.
setValue : Farklı bir Thread üzerinden işlemler gerçekleşirse, uygulama çökecektir. Atama işlemi hemen gerçekleşir.
postValue : Asenksron işlemlerin sonucunda değer ataması gerçekleşecekse kullanılır. setValue’ye göre yavaştır.
UI
ViewModel içerisindeki timer metodumuzu çağırdıktan sonra, time değişkenini gözlemliyoruz. Her değişim söz konusu olduğunda TextView yeniden yazma işlemi gerçekleştiriliyor.
Hadi gelin şimdi MVVM, Coroutine, Repository, Flow gibi durumlarda bu işler nasıl ilerliyor. Birazda o kısıma değinelim.
MVVM İçerisinde LiveData-Flow
MVVM içerisinde LiveData’da çeşitli değişikliğe gitmemiz gerekebilir.
Coroutine ile uzak sunucu işlemleri gerçekleştirilirken, suspend fonksiyonlara ihtiyaç duyulur. MVVM içerisinde, uzak sunucudaki datalara ulaşmak için Suspen fun ların tanımlanması Repository içerisinde olmalıdır diye bir görüş mevcut. ViewModel tarafında ise repository deki fonksiyonu CoroutineScope içerisinden çağırırız.
Flow’lar ile birden fazla return işlemleri gerçekleştirilebilir.
Flow
LiveData da olduğu gibi değişimi gözlemleyebilir, farklı yapıları bu değişimden haberdar edebiliriz. Fakat LiveData’nın yerine tamamen Flow’a geçiş için henüz erken, üzerinde belli geliştirmelerin daha yapılması gerekmektedir.
- Birden fazla asynchronous hesaplanmış değer döndürebilir.
- Bağlı olduğu coroutineScope cancel edildiğinde flow lifecycle sonlandırılır.
- Flow içerisinde suspend fonksiyonları çağırabilirsiniz.
- LiveData’ya göre Test yazımı daha kolaydır.
flow.map : Gelen data üzerinde çeşitli işlemleri farklı thread üzerinde gerçekleştirebilirsin. Örneğin gelen bir data’da ki fahrenhayt - derece dönüşümünü gerçekleştirebilirsiniz.
flow.onStart : Flow ilk çağırıldığında yapılacak tanımlamayı ifade eder.
flow.flowOn : Dispatcher.Default gibi ayrıştırma gerçekleştirilebilir.
flow.catch : Flow daki catch’leri yakalayabilirsiniz. Kendisine kadar olan durumdaki catch’leri yakalar.
flow.asLiveData : Flow -LiveData dönüşümü gerçekleşir.
flow.filtre : Normal listedeki filtreleme gibi asenkron olarak filtreleme yapabilirsiniz.
emit : Return değer iletmek için kullanılır.
Daha önceden yaptığımız bir uygulama üzerinden anlatımda bulunacağım. Yazının sonunda dilerseniz github dan projeyi inceleyebilirsiniz.
Resource
Datanın ifade edilebilmesini kolaylaştırmak ve işlemleri daha rahat kontrol edebilmek için Resource.kt oluşturuyoruz.
APIService
Uzak sunucuya atılacak isteği coroutine ile yapacağımız için suspend fun kullanıyoruz.
Repository
Repository içerisinden getPrayData fonksiyonu ile APIService deki getData fonksiyonunu çağırıyoruz. emit ,datanın durumu ile alakalı geri dönüşleri gerçekleştiriyor.
ViewModel
ViewModel içerisindeki getPrayData fonksiyonu ile Repository deki metodu çağırıyoruz. Başlangıç olarak ekranda proggressBar gözükmesi için onStart tanımlamasında emit işlemi gerçekleştiriliyor. Daha sonra asLiveData ile flow-liveData dönüşümü gerçekleştiriyoruz ve son olarak kullanacağımız coroutineScope’u belirtiyoruz.
UI
Fragment da, ViewModel içerisindeki getPrayData fonksiyonunu observe ediyoruz. Böylelikle her emit işleminde homeViewModel. resourceStatusData metodu tetiklenecek. Dilerseniz Observer içerisinden çeşitli companentler üzerinde değişiklik veya metot çağırımında bulunabilirsiniz.
ViewModel içerisindeki resourceStatusData metodu ile status’a göre progressBar, hata text veya dataların recyclerView da gösterilmesi sağlanıyor.
Proje içerisindeki kodların tamamına Github linkinden ulaşabilirsiniz.
Android Observer Desing Pattern, LiveData, Flow gibi konulara elimden geldiğince değinmeye çalıştım. Umarım faydalı olmuştur. Sağlıklı Günler.