Huawei Network Kit ile Android Ortamında Network İşlemleri
Selamlar, bu yazımızda Huawei Network Kit’ in özelliklerine ve kullanımına değineceğiz. Daha sonra da Rest API ile nasıl kullanılacağını örnek proje geliştirerek inceleyeceğiz. Uygulamamızı geliştirirken Kotlin dilini ve Android Studio ortamını kullanacağız. Son olarak da Android’ de network işlemlerini yaparken karşılaşabileceğimiz potansiyel hatalar ile bunlardan nasıl kaçınabileceğimiz hakkında konuşacağız.
Huawei Network Kit
Network Kit servisi bizim network işlemlerimizi hızlı ve güvenli bir şekilde gerçekleştirmemizi sağlayan yapıdır. REST API ile kolaylıkla kullanabildiğimiz gibi ekleyeceğimiz anotation lar (ek bilgi, açıklama) ile senkron ve asenkron network istekleri gönderebilmemizi sağlamaktadır. Ayrıca bizim yine hızlı ve güvenli bir biçimde dosya yükleme (upload ) ve indirme (download) işlemlerini, çoklu görevleri (multitasking), çoklu kullanımı (multithreading), devam edilebilir indirme ve yükleme işlemlerini yapabilmemize olanak sağlıyor. Son olarak ise, Network Kit’ i diğer Huawei Kitleri olan hQUIC Kit ve Wireless Kit ile daha hızlı network trafiği almak için birlikte kullanabiliyoruz.
Örnek Projemiz
Bu uygulamada Rest Servisler yardımıyla aldığımız kullanıcı listesini uygulamamızın ekranında göstereceğiz. Bunu geliştirirken aşağıdaki kütüphaneleri kullanacağız:
- RecyclerView
- DiffUtil
- Kotlinx Serialization
- ViewBinding
Uygulamamızı basit tutmak amacıyla MVVM gibi bir mimari yapı kullanmayacağız ve veriler yüklenirken kullanıcılara bir progress bar göstermeyeceğiz.
Örnek uygulamamızın dosya yapısını aşağıda görebilirsiniz.
Rest API İçin Kullanacağımız Web Sitesi
JsonPlaceHolder istediğimiz zaman test işlemleri için bize sahte veriler (fake data) sunan ücretsiz bir web sitesidir. Biz aşağıdaki bağlantıda bulunan sahte kullanıcı verilerini kullanacağız. Bu bağlantı bize kullanıcı listesini JSON formatında vermektedir.
https://jsonplaceholder.typicode.com/users
Neden Gson Yerine Kotlinx Serialization Kullanacağız?
İlk olarak, Rest API tarafından gelen JSON verilerini objelere dönüştürerek kolayca işlem yapabilmek için bir kütüphaneye ihtiyacımız var. Gson kütüphanesi JSON verilerini Java objelerine dönüştürmede ve tam tersini gerçekleştirmede en popüler olanlardan bir tanesi. Fakat biz Kotlin dilini kullandığımız için Gson bu işlemler için pek uyumlu değil. Çünkü Gson Kotlin’ deki non-null tiplerin bilgisini içermiyor.
Eğer bir String veriyi GSON ile ayrıştırmaya (parse) çalışırsak, bunun Kotlin deki varsayılan değerler (default values) hakkında bir bilgiye sahip olmadığını görürüz ve bize hata olarak NullPointerExceptions hatasını döndürür. Bu sebeple biz uygulamamızda Kotlinx Serialization kütüphanesini kullanacağız. Fakat siz Kotlin desteği sunan Jackson veya Moshi gibi diğer kütüphaneleri de kullanabilirsiniz. Kotlinx Serialization entegrasyonuna ve detaylarına yazımızın ilerleyen kısımlarında değineceğiz.
Projenin Kurulumu
Huawei HMS Core’ u projelerimize nasıl entegre edebileceğimizin detaylarına bu yazımızda değinmeyeceğiz. Resmi dokümanlar ya da Codelab yardımıyla HMS Core’ u projenize kolayca entegre edebilirsiniz. HMS Core’ u projemize entegre ettikten sonra, gerekli bağımlılıkları (dependencies) projemize ekleyelim.
Gerekli bağımlılıkları build.gradle (app level) dosyamıza ekleyelim.
Biz projemizde findViewById yerine viewBinding kullanacağız. Bu her bir XML layout dosyamız için bir binding class generate edecektir. Bu binding class ların instance ları yardımıyla view ların tiplerini görerek, null safety olarak erişebileceğiz.
Kotlinx Serialization kütüphanesinin son versiyonu olan 1.1.0 yerine biz kotlinx-serialization-json:1.01 versiyonunu kullanacağız. Eğer 1.1.0 versiyonunu veya daha üstünü kullanmak isterseniz, projenizdeki Kotlin versiyonunuzun en az 1.4.30-M1 versiyonu olması gerekiyor. Aksi takdirde aşağıdaki hata ile karşılaşırsınız:
Your current Kotlin version is 1.4.10, while kotlinx.serialization core runtime 1.1.0 requires at least Kotlin 1.4.30-M1.
Gerekli bağımlılıkları build.gradle (project level) dosyamıza ekleyelim.
Gerekli Network İzinlerini Tanımlama
Network Kit’ in fonksiyonlarını kullanmak istiyorsak AndroidManifest.xml dosyamıza gerekli izinleri tanımlamamız gerekiyor.
Network Kit Initialize (Başlatma) İşlemi
Bir Application class oluşturalım ve Network Kit’ i burada initialize edelim.
Not: App class ınızı oluşturduktan sonra Android Manifest dosyasına eklemeyi unutmayınız.
<manifest ...>
...
<application
android:name=".App"
...
</application>
</manifest>
ApiClient
getApiClient() -> Bu fonksiyon RestClient instance ını Singleton olarak bize döndürmektedir. Göndereceğimiz isteklerdeki bağlantının zaman aşımı süresini burada belirleyebiliriz. Ayrıca kullanacağımız base URL’ i de burada belirtebiliriz.
ApiInterface
Burada request (istek) tipini GET olarak belirtiyoruz ve base URL imize “users” anahtar kelimesini ekleyerek istek göndereceğimizi belirtiyoruz. Bu da sonuçları bize String tipinde döndürecektir.
User — Model Class
Biraz önce bahsettiğimiz gibi veriler bize String tipinde dönüyor. Sonrasında bunu Kotlinx Serialization kütüphanesini kullanarak User objelerine dönüştüreceğiz. Bu işlemi gerçekleştirmek için data class ımıza bazı anotation lar eklemek zorundayız.
@Serializable -> Bu anotation ile class ımızın serializable bir class olduğunu belirtiyoruz.
@SerialName() -> Varsayılan olarak gelen verimizdeki değişken isimleri ile burada kullandığımız değişken isimleri aynı olmak zorunda. Eğer farklı bir değişken ismi kullanmak istersek, ilgili değişken isminin üzerine @SerialName anotation ını ekleyerek parantez içerisinde RestAPI tarafından gelen değişken ismini yazıyoruz.
UserDiffUtil
RecyclerView’ a listedeki ögelerin değiştiğini haber vermek için klasik kullanım olan notifyDataSetChanged() yerine DiffUtil kullanacağız.
DiffUtil iki liste arasında karşılaştırma yaparak, ikinci listedeki değişikleri mevcut listeye eklememizi sağlayan bir yardımcı class. Bu karşılaştırmayı yaparken de hesaplama metodu olarak “The Myers Difference Algorithm” kullanıyor.
Klasik yöntemdeki notifyDataSetChanged() kullanımını verimsiz kılan sebep ise, listede bir öge değişse bile görünen tüm view ları tekrar oluşturmaya zorlamasıdır. Dolayısıyla bu da gereksiz operasyon maliyetlerine neden olmaktadır.
row_user.xml
Burada userId ve userName gösterebilmek için iki tane TextView bulunuyor. Bu layout dosyasını RecyclerView’ da kullanacağız.
UserAdapter
Bu classımız adapter ve ViewHolder class ını içeriyor.
activity_main.xml
Burada kullanıcı listesini göstermek için kullanacağımız recyclerview yer alıyor.
MainActivity
userAdapter — RecyclerView için bir adapter oluşturduk.
apiClient — RestClient objesini (ApiClient) kullanarak API objesi isteği oluşturduk.
Network Kit bize network isteği gönderebilmek için iki tane yol sunuyor: synchronous (senkron) ve asynchronous (asenkron).
- Synchronous istekler operasyon tamamlanıncaya kadar mevcut client’ ı bloklar. Görev bittikten sonra da bize veriyi iletir.
- Asynchronous istekler mevcut client’ı bloklamazlar ve veriler geldiğinde callback yardımıyla bize iletirler.
getUsersAsSynchronous() —Synchronous istekleri burada kullanıyoruz. İlk olarak RestAPI tarafından response (cevabı) alıyoruz. Sonrasında bu dönen JSON verisini User objesine dönüştürüyoruz. Bu işlem için decodeFromString fonksiyonunu kullanıyoruz. Ayrıca ignoreUnknownKeys = true olarak işaretliyoruz. Çünkü biz JSON dosyası içerisindeki tüm verileri kullanmak istemiyoruz. Biz sadece kullanıcıların id, name, username ve email verileri ile ilgileniyoruz. Eğer çektiğiniz veride bulunan tüm değişkenleri Model Class (User) içerisine koymazsanız ve bu değeri yani ignoreUnknownKeys değerini true olarak işaretlemezseniz aşağıdaki gibi bir hata ile karşılaşırsınız:
Use ‘ignoreUnknownKeys = true’ in ‘Json {}’ builder to ignore unknown keys.
Bunların dışında biz bu fonksiyonu onCreate içerisinde çağırıyoruz. Fakat biz varsayılan olarak main thread içerisinde bulunuyoruz ve bu fonksiyonu doğrudan main thread içerisinden çağırırsak aşağıdaki hata ile karşılaşırız:
Caused by: android.os.NetworkOnMainThreadException
Bu hata ile karşılaşmamak için getUsersAsSynchronous() fonksiyonunu farklı bir thread içerisinde çağırıyoruz. Sonrasında, verilerimizi başarıyla elde etmiş oluyoruz. Fakat hala bir sorunumuz var. Biz veriyi çekmek için thread imizi değiştirdik ve main thread e geri dönmeden uygulamamız içerisindeki view ları değiştiremeyiz. Eğer main thread’ e dönmeden, view üzerinde bir değişiklik yapmaya çalışırsanız aşağıdaki hata ile karşılaşırsınız:
D/MainActivity: onFailure: Only the original thread that created a view hierarchy can touch its views.
Bu sebeple kodumuzu main thread üzerinde çalıştırmak için runOnUiThread fonksiyonunu kullanacağız. Son olarak da verilerimizi ekranda liste halinde görüntülemek için recycler adapter’ ına göndereceğiz.
getUsersAsAsynchronous() —Burada ise asynchronous olarak isteğimizi kullanıyoruz. Bir network isteği gönderiyoruz ve mevcut thread imizi bloklamadan bir yanıt bekliyoruz. Yanıt geldiğinde ise verilerimizi liste şeklinde ekranda gösteriyoruz. Burada ek bir işlem yaparak asynchronous fonksiyonumuzu farklı bir thread üzerinde çalıştırmamıza gerek kalmıyor. Fakat uygulamadaki herhangi bir view’ a erişmek istersek yine main thread’ e geçmek zorundayız. Bunun için de runOnUiThread fonksiyonumuzu kullanarak main thread’ e geçebiliriz ve verilerimizi gösterebiliriz.
İpuçları & Tüyolar
- Thread operasyonlarını yönetmek ve asenkron işlemlerini kolay bir şekilde gerçekleştirmek için Coroutines kullanabilirsiniz.
- Network isteklerimizin sonuçlarının başarılı veya başarısız olarak verdikleri dönüşleri kontrol etmek için Sealed Result Class lardan yararlanabilirsiniz.
- Network istekleri göndermeden önce, kullanıcıların internet durumlarını kontrol etmek için ConnectivityManager kullanabilirsiniz.
Sonuç
Bu yazımızda özet olarak Network Kit’ i network işlemlerimizde nasıl kullanabileceğimizi öğrendik. Bunu öğrenirken de REST Server’ den elde ettiğimiz kullanıcı listesini ekranda gösterebildiğimiz örnek bir uygulama geliştirdik. Ek olarak, HttpClient objesini ya da RestClient objesini kullanarak network isteği göndermenin yanında Network Kit bizlere dosya yükleme ve indirme özellikleri de sunmaktadır. Karşılaştığınız sorunları veya sorularınızı yorum olarak yazabileceğiniz gibi aşağıdaki bağlantı aracılığıyla Huawei Geliştirici Forumu üzerinden de sorabilirsiniz.
Zaman ayırdığınız için teşekkürler, umarım yararlı olmuştur. Bir sonraki yazımızda görüşmek üzere…
Referanslar
Huawei Network Kit Resmi Dokümanı
Huawei Network Kit Resmi Codelab
Huawei Network Kit Demo App Resmi Github