Jetpack WorkManager: Network Entegrasyonu



Herkese selamlar,


Bugün daha önceden de bahsettiğimiz Android Jetpack'le birlikte gelen WorkManager konusu hakkında detaylı bir app yapacağız. WorkManager kullanımının yanı sıra farklı framework ve library'lerden de yaralanarak, bunlarla birlikte WorkManager entegrasyonun nasıl çalıştığı/kullanıldığını öğreneceğiz.


Eğer WorkManager'ı daha önceden bilmiyorsanız, WorkManager konusu hakkında yazdığım Jetpack: WorkManager Temel Kullanımı yazımı okumanızı kesinlikle tavsiye ederim.


WorkManager'ların en çok kullanıldığı alanlar API'ler ve uzak sunuculardır. Bu sebeple bu uygulamamızda çok güzel bir gerçek kullanım senaryosu oluşturacağız. Uygulamamızda WorkManager haricinde Retrofit, Rxjava, RxWork, Picasso ve MpAndroid library ve framework'lerini kullandık. Asıl yazı konumuzun bunlar olmadığı için anlatılması çok elzem olan yerler hariç bunlara pek değinmeyeceğiz. Bu nedenle sizlerin bu konulardan bir veya daha fazlasını bilmeme ihtimaline karşı linkleri bırakıyorum.


Retrofit:

https://www.mobiler.dev/post/kotlin-ile-retrofit-kutuphanesi-entegrasyonu

Rxjava:

https://www.raywenderlich.com/2071847-reactive-programming-with-rxandroid-in-kotlin-an-introduction

Picasso:

https://square.github.io/picasso/

RxWorker:

https://developer.android.com/topic/libraries/architecture/workmanager/advanced/rxworker

MpAndroidChart:

https://github.com/PhilJay/MPAndroidChart


(RxWorker ve MpAndroidChart'a kendim de değineceğim için çok az göz gezdirseniz ve build.gradle kısımlarını halletseniz yeter bile)


Uygulamamız, ülkeler ve o ülkelerin en kalabalık şehirlerinin isimlerini, logolarını, nüfuslarını veren, kıtalar ve o kıtaların en kalabalık şehirlerinin isimlerini, logolarını, nüfuslarını veren, kendi oluşturduğum iki API'den değer çekecektir. Sonrasında bu değerler üzerinde değişikler yapılarak grafik gösterim için son değerler oluşturulacak. En sonunda da bu iki değeri tek bir Worker'da birleştirerek grafik karşılaştırması yapılacaktır. Api'leri collectapi sitesi üzerinden oluşturdum. İsterseniz sizler de kendi api'lerinizi oluşturup kendi örneğinizde kullanabilirsiniz.


Bizler bu uygulamamızda api'lerin main url'lerini kullanacağız, bunun için de uygulama içinden authorize işlemi gerekli. Ben sizler için OkHttp ile genel olarak authorize işlemini projede yazıp yorum satırı olarak bıraktım. Aynı zamanda bir diğer yöntem olan, request işlemleri için tek tek authorize ekleme işlemlerini de kodlarımıza ekledim.


Proje kodlarını inceleyip iki yöntemden birini kullanabilir veya api'lerin main url'si yerine test url'sini kullanarak authorize işlemlerini hiç yapmayabilirsiniz. Sizlere main url'ler authorize'sız görülmeyeceği için JSON formatında olan test url'lerinin linklerini bırakıyorum.


Country API: https://api.collectapi.com/run/test/5f53f464e24ad13d9a597485

Continent API: https://api.collectapi.com/run/test/5f53f2eee24ad13d9a597469


Aynı zamanda kendi API'nizi yazmak isterseniz diye örnek olması açısından kendi yazdığım Continent API'yi sizlere bırakıyorum.


 [
   {
     continent:"America",
     population:23,
     province:"New York City",
     logo:'https://cdn.britannica.com/14/3014-004-76F17405/flag-New-York-color-uniforms-facings-American-1909.jpg'
   }
   ,
   {
     continent:"Asia",
     population:37,
     province:"Tokyo-Yokohama",
     logo:'https://www.spoon-tamago.com/wp-content/uploads/2015/10/and-tokyo-logo-3.jpg'
   }
 ]

Üstte bazı temel senaryoları anlattığım için aynı konuları, yazının daha uzun olmaması için anlatmayacağım. Artık uygulamamıza geçebiliriz.


Entegrasyon


Uygulama adımlarını kısaca anlatmak gerekirse, beş Worker'dan oluşacaktır. Paralel çalışacak ilk iki Worker API'mizden verileri çekecektir. Bir sonraki adımda yine paralel çalışacak iki Worker, her bir API'nin "population" data'larını düzenleyecektir. En sonunda son Worker'ımız ise bu düzenlenmiş iki data'yı birlikte kullanarak bir grafik oluşturacaktır.




CountryWorker ve ContinentWorker'da önceki Worker örneklerinden farklı işlemler yaptığımızı fark etmişsinizdir. Bu fark RxWork kullanımıdır. Bunun sebebi bizler API veya uzak sunucudan veri alıp gönderirken en çok kullandığımız Retrofit ve RxJava ikilisinin normal şartlarda WorkManager ile kullanırken bazı sebeplerden dolayı bizlere uğraş vermesindendir. Bu sebepten RxJava ve WorkManager'ın birlikte rahat bir kullanımını sağlamak için bu yapı ortaya çıkmıştır. Bu yapının bizlere sağladığı kolaylık bir doWork içinde işlemlerimizi yapmak yerine createWork ile birlikte, klasik bir RxJava mantığına yakın bir şekilde işlemler yapmaktır. Yukarıda da bunu görmekteyiz.


İkinci bir fark ise outputData method'undadır. Önceki örneklerde String tipinde bir output üretirken şu anda gson yardımı ile bu işlem yapılmaktadır. Bunun sebebi Data'nın yapısından kaynaklıdır. Data bilinenin aksine veri saklama yöntemi değildir ve en fazla 10 KB'lik veri tutabilmektedir. Yani bizler API'den gelen verileri çoğunlukla bu boyut kısıtlamasından dolayı direk kullanamayabiliriz. Bu sebeple bizim object'lerimizin output olarak kullanılabilmesi için gson ile dönüşüm işlemleri yapmaktayız.


API'miz aslında birden çok elemana sahip olduğu için uygulamamızda liste olarak karşılanması gerekir. Bizler ise bu listenin bir elemanını alarak ContinentWorker ve CountryWorker'da tek bir output üretmekteyiz. Sizler isterseniz liste yapısı ile kendi uygulamanızı daha farklı şekilde inşa edebilirsiniz.




Bu iki ModifierWorker'da ise fark ettiğiniz gibi artık API'ler ile ilişiğimiz kalmadığı için bizler işlemlerimizi eskisi gibi doWork içinde yapmaktayız. İkinci olarak yapılan işlem, gson'lar ile oluşturulan output'ları tekrardan eski haline döndürerek object'lerin elde edilmesidir. Bu sayede bizler population'nın tipini grafiğimizi oluşturabilmek için değiştirebileceğiz. Bu değişiklik, integer tipinde olan population'nun artık float tipinde olması işlemidir. Bu işlem keyfi bir işlem değildir. Çünkü oluşturacağımız grafik, sayısal değer olarak bizlerden float tipini istemektedir. Değişken tiplerini her iki Worker'da da değiştirdiğimize göre artık son Worker'a geçebiliriz.



Bu Worker'da ise yaptığımız işlemler, iki float'ı bir float array şeklinde bir ara getimektir.


Aslında bu son Worker'ın bu kadar kolay işlem yapabilmesinden sonra sizler, bu işlemleri beş adet Worker ile yapmak yerine üç adet Worker ile de yapabileceğimizi düşünmüş olabilirsiniz. Aslında doğrusu evet, yapılabilir. Aklınızdaki bu soruyu çözmek adına, şimdi neden bu kadar Worker ile çalıştığımızı ve zincirleme mantığımızın işleyişinin ne şekilde olduğunu açıklayalım.


Öncelikle ilk iki Worker'ımız(CountryWorker, ContinentWorker) birbirleriyle paralel çalışan Worker'lardır. Yani bir Worker başarılı olup diğeri başarısız olursa işlemler zincirin ikinci halkasına geçememektedir. Eğer ilk iki Worker koşulları sağlayıp başarılı olursa bizler UI'mızda bu işlemlerden elde ettiğimiz output'ları belli bir format ile göreceğiz. Sonrasında çalışmaya başlayan iki adet ModifierWorker'larımız ise yine aynı mantıkta birbirleri ile paralel çalışan Worker'lardır.


Bizim iş mantığımızda ne olursa olsun API'lere bağlanıp gerekli bilgilere ulaşmak ana hedefimizdir. Daha sonrasında yapılacak modifikasyon işlemlere ve grafik gösterimi ise birazcık daha lükse kaçan işlemlerdir. Bu sebeple bu iki Worker'da, ileride MainActivity'de göreceğiniz gibi mobil cihazınızın şarja bağlanma koşulu aranmaktadır. Cihaz şarja bağlı olmadığı sürece bu iki Worker çalışmayacaktır. Aslında bu işlemi şöyle düşünebilirsiniz. Bizim burada yaptığımız modifikasyon, cihazı yoran ve şarj seviyesini çok hızlı bir şekilde azaltan bir işlemdir. Biz de bu tür sorunların ileride işleyişimizi aksatmaması ve çok da mecburi bir işlem olmaması sebebiyle, oluşturduğumuz constrait'ler ile uygulamamıza yön vermiş ve Worker'ların çalışmasını bir düzene oturtmuş oluyoruz.


DetailWorker'da ise tekrardan bir şarj olma koşulu ile, artık grafik için bir float array output'u oluşturuyoruz.


Aslında bunları anlattıktan sonra sizlerin de kafalarınızda belli başlı şeylerin oturduğunu düşünüyorum. Bildiğimiz gibi bir uygulama yaparken sadece uygulamanın çalışması önemli olan bir husus değildir. Uygulamanın verimli çalışması, önceliklerinin olması, belirli hata senaryolarına hazırlıklı olması ve bu hata veya beklenmeyen aksiliklerde uygulamamızın en azından kullanıcıya belli başlı bilgileri iletmesi de çok önem arz etmektedir. WorkManager mantığı da aslında tam olarak budur. Bir uygulamanın ana iskeletini oluşturmaktadır. Yapılan işlemlerin sırası ve işleyişine göre belli başlı koşullar istemekte ve bu koşulların olumluysa sonucunu oluşturmaktadır. İşlem olumsuz olma durumlarında ise olumlu olana kadar hazır bir şekilde arka planda, pil tüketimini gözeterek beklemektedir.


Artık son olarak MainActivity'imize geçip, WorkManager ile ilgili yapılan işlemleri anlatabiliriz.



Burada öncelikle Constraints'lermizi oluşturuyoruz. Sonrasında WorkRequest'lerimizi, bu constraints'leri de kullanarak hazırlıyoruz.


Bir WorkManager oluşturup daha önceden anlattığımız zincirleme işlemlerini oluşturuyoruz. Sonrasında ise LiveData yardımı ile bu request'lerin id'lerinden yaralanarak, Worker işlemlerini takip ediyoruz ve geriye dönen output'lari burada yakalayıp UI'a yansıtıyoruz. Sizler isterseniz LiveData, id ikilisi yerine her bir request'e bir tag atayarak bu takip işlemlerini yapabilirsiniz. Ama benim önerim bu yöntemin daha iyi olması yönündedir.

Bütün request'ler olumlu olarak sonuçlandığı takdirde UI'da sırası ile her request'in sonuçlarını çok rahat bir şekilde görebilmekteyiz. Tabi bu olumlu sonuçlanma işlemlerinin daha önceden de anlattığımız gibi bir anda olmasına gerek yok. Yani uygulama çalıştıktan sonra ilk iki paralel çalışan Worker'larımızın network isteğini karşılayamayabilir. Yarım saat sonra bu koşulu karşılama işlemi gerçekleştikten sonra ilk verilerimizi görebiliriz. Sonrasında tekrardan geriye kalan Worker'larımız şarj olma işlemini karşılayamayabilir ve belli bir süre sonra bu istek de karşılandıktan sonra WorkManager bu karşılama işlemini algılayıp geri kalan işlemleri gerçekleştirip bizlere bir grafik oluşturur ve uygulamamız tamamlanarak görevini gerçekleştirmiş olur.


Resim 1: İki paralel WorkRequest'in network koşulu sağlanmamış.

Resim 2: Network koşulu sağlanmış ama şarj olma koşulu sağlanmamış.

Resim 3: Bütün koşullar sağlanmış.


Uygulamanın bütün kodlarına ulaşmanız ve birebir aynı işlemleri yapmanız için sizlere aşağıda GitHub reposunu bırakıyorum. Hepinize güzel çalışmalar dilerim.


GitHub: https://github.com/mskinik/RxWorkAPIConnection


Yazı için faydalandığım kaynaklar:

#workmanager #android #kotlin


Komünite

Platform

Mobiler.dev Anasayfa
  • Twitter
  • Instagram
  • development_düzenlendi_düzenlendi
  • Youtube
  • slack-icon-black_edited_edited_edited
  • Gri LinkedIn Simge
JetBrains Hakkında Detaylı Bilgi Alın

© 2020 by mobiler.dev

mobilerdevLogo.jpg
Yazarlık Başvurusu Hakkında Bilgi Alın, Başvuru Yapın.
Topluluk Yazarlarını Tanıyın