OʻZBEKISTON RESPUBLIKASI OLIY TA’LIM, FAN
VAINNOVATSIYALAR VAZIRLIGI
MIRZO ULUGʻBEK NOMIDAGI OʻZBEKISTON
MILLIYUNIVERSITETINING JIZZAX FILIALI
AMALIY MATEMATIKA FAKULTETI
«KOMPYUTER ILMLARI VA DASTURLASHTIRISH» kafedrasi
“ MOBIL ILOVALARNI YARATISH” FANIDAN
MUSTAQIL ISH
Mavzu: Retrofit (Android) va Alamofire (iOS) kutubxonalari bilan API
chaqiriqlari
Bajardi: “Kompyuter ilmlari va dasturlash texnologiyalari” yoʻnalishi
4-kurs 10-21-guruh talabasi Esirgapov Abdumumin
Tekshirdi: Ulashev Asror
Jizzax – 2024
Retrofit (Android)
•
•
•
•
•
Retrofit – bu Android ilovalarida RESTful API’lar bilan ishlashni osonlashtiradigan
kutubxona.
U HTTP chaqiriqlarini oddiy Java interfeyslari orqali aniqlash imkonini beradi.
Retrofit JSON formatidagi javoblarni avtomatik ravishda Gson yoki Moshi kabi parserlar
yordamida Java obyektlariga aylantiradi.
Asinxron chaqiriqlarni Callback interfeysi yoki Kotlin Coroutines yordamida qo‘llabquvvatlaydi.
Ko‘p formatdagi kontentlarni, shu jumladan FormUrlEncoded va Multipart formatlarini
qo‘llab-quvvatlaydi.
Alamofire (iOS)
•
•
•
•
•
Alamofire – bu Swift tili asosida iOS ilovalarida API bilan ishlash uchun keng
qo‘llaniladigan kutubxona.
U HTTP so‘rovlar va JSON javoblarni boshqarish uchun qulay interfeysga ega.
Alamofire so‘rovlarni boshqarish uchun URLSession sinfiga asoslanadi va asinxron
ishlashni osonlashtiradi.
JSON-ni avtomatik ravishda Swift modellari bilan ishlash uchun Codable protokoli
orqali dekodlaydi.
Retry, offline caching, va HTTPS sertifikatlarini boshqarish kabi qo‘shimcha
funksiyalarni ham taqdim etadi.
Umumiy jihatlari
•
•
•
Ikkala kutubxona ham asinxron ishlashni qo‘llab-quvvatlaydi, ya’ni foydalanuvchi
interfeysi API chaqiriqlari bajarilguncha bloklanmaydi.
Moslashtirilgan header va parametrlar qo‘shish imkonini beradi, bu esa autentifikatsiya
yoki maxsus so‘rovlar uchun juda qulay.
JSON ma'lumotlarini model obyektlariga avtomatik dekodlash imkoniyati mavjud, bu esa
ma'lumotlar bilan ishlashni soddalashtiradi.
Retrofit’ning qo‘shimcha imkoniyatlari va konfiguratsiyalari (Android)
•
•
•
•
Base URL: Retrofit’da barcha so‘rovlar uchun umumiy asosiy URL (Base URL)
belgilanadi, keyin esa endpointlar shunga qarab aniqlanadi.
Converter Factory: Retrofit turli ma'lumot formatlarini avtomatik o‘zgartirish
imkoniyatini beradi. GsonConverterFactory JSON ma'lumotlarini Java obyektlariga
aylantiradi, lekin ScalarsConverterFactory oddiy matn ko‘rinishidagi javoblar bilan
ishlash uchun qo‘llaniladi.
Error Handling: Retrofit so‘rovlar xatolarini (HTTP error yoki Network error)
Response yoki Throwable obyektlari orqali qaytaradi. Bu esa xatoliklarni turli holatlarga
qarab boshqarishni osonlashtiradi.
Interceptors: OkHttp bilan birgalikda Interceptorlardan foydalanib, so‘rov va javoblar
ustida ishlash, ularni loglarda ko‘rish yoki autentifikatsiya tokenlarini qo‘shish mumkin.
Alamofire’ning kengaytirilgan imkoniyatlari (iOS)
•
Session Management: Alamofire’da Session sinfi mavjud bo‘lib, u orqali bir nechta
API chaqiriqlarini boshqarish va har xil konfiguratsiyalar qo‘llash mumkin. Misol uchun,
qo‘shimcha header qo‘shish yoki maxsus timeout sozlash mumkin.
•
•
•
Request Retrying: Tarmoq uzilishlari yoki boshqa xatolardan keyin so‘rovlarni qayta
yuborish imkoniyatini beradi. Alamofire’da maxsus qayta urinish strategiyalarini sozlash
mumkin.
Upload & Download Management: Alamofire’da katta fayllarni yuklash va yuklab
olish uchun qulay vositalar mavjud. ProgressHandler orqali yuklash va yuklab olish
jarayonining foiz ko‘rsatkichlarini kuzatish mumkin.
Response Caching: Alamofire so‘rovlarni keshlashni qo‘llab-quvvatlaydi. Bu tarmoqqa
kirish cheklangan vaqtda keshlangan ma'lumotlarni ishlatish imkonini beradi.
Retrofit va Alamofire orqali asinxron ishlash
•
•
Kotlin Coroutines (Retrofit): Retrofit Kotlin korutinlari bilan mos ravishda ishlaydi. Bu
esa suspend funksiyalar orqali API chaqiriqlarini ancha oson boshqarish imkonini beradi
va natijada kod soddalashadi.
Completion Handlers va Promises (Alamofire): Alamofire so‘rovlarni completion
handlers orqali boshqaradi, lekin PromiseKit kutubxonasi bilan birgalikda ishlash ham
mumkin, bu esa ayniqsa qator asinxron so‘rovlarni boshqarishda yordam beradi.
Autentifikatsiya va xavfsizlik
•
•
OAuth va JWT bilan ishlash (Retrofit): Retrofit OkHttp Interceptor orqali
so‘rovlarga token qo‘shish imkonini beradi. Bu ayniqsa JWT (JSON Web Token) va
OAuth autentifikatsiyasi uchun muhim.
HTTPS Sertifikatlari va Pinning (Alamofire): Alamofire xavfsizlik jihatidan SSL
pinning funksiyasini qo‘llab-quvvatlaydi, bu esa foydalanuvchi va server orasidagi aloqa
xavfsizligini ta’minlashda qo‘l keladi.
Ma’lumotni qayta ishlash va validatsiya
•
•
Retrofit (Model Validation): JSON ma'lumotlari model obyektlariga aylantirilgandan
so‘ng, Moshi yoki Gson yordamida ma'lumot validatsiya qilinadi, noto‘g‘ri yoki yo‘q
qiymatlarda xatolikni oson kuzatish mumkin.
Alamofire (Response Validation): Alamofire-da ma'lumotlarni qayta ishlash jarayonida
xatoliklarni tekshirish uchun validate() funksiyasi qo‘llaniladi, bu orqali qator xatolik
holatlarini boshqarish imkoniyati mavjud.
biz Moshi deb nomlangan JSON kutubxonasi haqida gapiramiz. Moshi bizga JSONni
serialize va deserialize qilish yordam beradi. Ya’ni bunda JSON ko’rinishdagi matn formatidan
obyekt yoki ro’yxatga o’tkazish hamda buning aksi nazarda tutilmoqda.
Shunday qilib, boshlashdan oldin, maqolani quyidagi bo’limlarga ajratamiz.
•
Nega bizga androidda serialize va deserialize qilish uchun kutubxona kerak?
•
Moshi-dan qanday foydalanamiz?
•
Moshining xususiyatlari
•
Moshi-ni ro’yxat bilan ishlatish.
•
Moshi-ni retrofit bilan ishlatish
Nega bizga androidda serialize va deserialize qilish uchun kutubxona kerak?
Android-da, biz API orqali so’rov yuborganimizda, ko’pincha JSON matn ko’rinishida javob
olamiz. Biz bu JSON ko’rinishida matnni qo’lda tahlil qilishimiz va u bilan ishlashimiz yoki
serialize and deserialize uchun Moshi kabi kutubxonadan foydalanishimiz mumkin. Moshi-dan
foydalanish biz yozadigan satrlar sonini kamaytirishga va xato qilish ehtimolini kamaytirishga
yordam beradi.
Moshi-dan qanday foydalanamiz?
Bu bo’limda biz Moshi bilan qanday ishlashimizni tushunamiz.
Aytaylik, bizda data class bor, quyidagi ko’rinishda:
data class User(val name: String, val email: String)
va bizda User classdan obyekt olib user deb o’zgaruvchiga nom beramiz.
val user = User("Himanshu", "himanshu@gmail.com")
Endi Moshi yordamida biz uni JSON tuzilishiga aylantiramiz. Moshi bilan ishlash uchun bizda
JsonAdapter klassi bor.
Biz Moshi-ni yaratamiz,
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
va biz shuningdek JsonAdapter turidagi o’zgaruvchini yaratamiz, bu bizga JSON-ni Object
sinfiga aylantirishda yordam beradi va aksincha.
val jsonAdapter: JsonAdapter<User> = moshi.adapter(User::class.java)
Bu yerda biz foydalanuvchi ma’lumotlari sinfini harakatlarni bajarishni xohlagan tuzilma sifatida
o’tkazdik. Endi, User classidan olgan obyektimizni biz foydalanadigan JSONga aylantirish uchun,
jsonAdapter.toJson(user)
Bu yerda biz user obyektini JSON matn formatiga o’tkazish uchun toJson funksiyasidan
foydalanmoqdamiz va agar biz buni konsol chiqarib ko’rsak,
{"email":"himanshu@gmail.com","name":"Himanshu"}
Xuddi shunday, biz JSON formatidagi matnni Moshi-dan foydalanib obyektga qayta
o’tkazishimiz mumkin. Aytaylik, biz yuqoridagi JSONni User classidagi obyektga
aylantirmoqchimiz,
jsonAdapter.fromJson("{\"email\":\"himanshu@gmail.com\",\"name\":\"Himanshu\"}")
Biz bu yerda fromJson funksiyasidan foydalanmoqdamiz, bu bizga o’tgan JSON-ni obyektga
aylantirishga yordam beradi. Endi, agar biz buni konsolga chiqarib ko’rsak,
User(name=Himanshu, email=himanshu@gmail.com)
Moshi yordamida biz JSONni obyektga aylantiramiz va obyektni JSONga.
Moshining xususiyatlari
Moshi deyarli barcha ma’lumotlar turlarini qo’llab -quvvatlaydi, masalan:
•
Butun, haqiqiy va boshqalar
•
Massivlar va kollektsiyalar(collections)
•
String
•
Enums
Moshida biz yuqorida aytib o’tilganlardan tashqari o’z turimizni yaratishimiz mumkin. Keling,
buni misol bilan tushunaylik,
Keling, User classiga o’zgartirishlar kiritamiz,
data class User(val name:Name)
Bu erda biz “Name” nomli yangi ma’lumotlar classini qo’shdik, u quyidagicha ko’rinadi:
data class Name(val firstName: String, val lastName: String)
Bu yerda, Name classida firstName va lastName deb nomlangan ikkita maydon bor.
Endi, bu sinfdan JSON olayotganda, foydalanuvchining to’liq ismi, birinchi ism keyin familiya
(firstName+lastName) bo’lishini xohlayman. Yoki biz har safar JSONni tahlil qilganda qo’lda
qila olamiz yoki biz uchun Moshi yordamida o’z adapterimizni qo’shishimiz mumkin.
Biz NameAdapter deb nomlangan class yaratamiz.
class NameAdapter { }
Va bu sinf ichida biz o’z konvertatsiyamizni qilmoqchimiz. Biz nomlangan ikkita funktsiyani
qo’shamiz fun fullName() va fun getIndividualNames()
Bu class strukturasi quyidagicha:
class NameAdapter {
@ToJson
fun fullName(name: Name): String {
} @FromJson
fun getIndividualNames(json: String): Name {
}
}
Bu shuni anglatadiki, ushbu adapterni Moshi bilan ishlatganda, Moshi annotatsiyalarni qidiradi.
Aytaylik, biz to’liq ismni qaytarish va JSONda qaytarish uchun ism va familiyani
birlashtirmoqchimiz. Biz buni ToJson bilan izohlangan fullName funktsiyasida bajaramiz. Endi
fullName funksiyasi shunday bo’ladi:
@ToJson
fun fullName(name: Name) = name.firstName + " " + name.lastName
Biz JSONni tahlil qilish uchun ToJson konvertatsiyasini qo’shganimiz uchun, FromJson bilan
izohlangan getIndividualNames funksiyasini o’zgartirishimiz kerak, bu JSON formatidagi matnni
obyektga moslashtirishda Name data classini alohida elementlarga aylantiradi.
getIndividaulNames funksiyasi shunday ko’rinadi:
@FromJson
fun getIndividualNames(fullName: String): Name {
val name = fullName.split(" ")
return Name(name[0], name[1])
}
Bu yerda biz birinchi bo’sh joydan fullName qatorini ajratamiz va satrlar ro’yxatida ism va
familiya bo’lgan ikkita satrni olamiz.
Va nihoyat, ushbu adapterni ishlatish uchun biz uni Moshi obyektiga qo’shamiz:
val moshi = Moshi.Builder()
.add(NameAdapter())
.add(KotlinJsonAdapterFactory())
.build()
Eslatma: Moshi adapterlari birinchi navbatda chaqiriladi, shuning uchun siz har doim Kotlin
adapterini o’zingizning shaxsiy adapteringizdan keyin qo’shishishingiz kerak. Aks holda
KotlinJsonAdapterFactory birinchi o’ringa chiqadi va sizning maxsus adapterlaringiz
chaqirilmaydi.
JsonAdapter yuqoridagi kabi bo’ladi,
val jsonAdapter: JsonAdapter<User> = moshi.adapter(User::class.java)
va endi biz toJson va FromJsonni konsolga chiqarsak,
jsonAdapter.toJson(user)
va
jsonAdapter.fromJson("{\"name\":\"Himanshu Singh\"}").toString()
Biz quyidagi natijani olamiz,
{"name":"Himanshu Singh"}User(name=Name(firstName=Himanshu, lastName=Singh))
Shunday qilib, siz o’zingizning konvertatsiya adapteringizni yaratishingiz mumkin.
Keling, sinfdagi faqat bitta maydonga yoki bir xil turdagi har xil maydonlarga ba’zi shartlar
qo’yilishini xohlaymiz. Biz buni adapter yaratgan joyda ham bajarishimiz mumkin va bu faqat
aytilgan yagona maydonga ta’sir qiladi. Biz buni annotatsiya yordamida qilardik.
Birinchidan, biz shunday annotatsiya yaratamiz:
@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class EmailCheck
Bu yerda elektron pochtani tekshirish maxsus maydonlar bilan ishlaydigan JsonQualifier
annotatsiyadan foydalanilgan.
Endi biz User classini o’zgartiramiz,
@JsonClass(generateAdapter = true)
data class User(val name: Name, @EmailCheck val email: String?)
Bu yerda biz elektron pochtani EmailCheck annotatsiyasini qo’yganimizni ko’rishingiz mumkin,
ya’ni barcha EmailCheck annotatsiyasi endi faqat elektron pochta maydonida ishlaydi. Name
classi o’zgarmaydi.
Endi biz ikkita funksiyaga ega adapterni yaratamiz, ya’ni toJson va fromJson:
class EmailAdapter {fun String.isValidEmail(): Boolean {
return !TextUtils.isEmpty(this) && Patterns.EMAIL_ADDRESS.matcher(this).matches()
}@ToJson
fun toJson(@EmailCheck email: String?) = email@FromJson
@EmailCheck
fun fromJson(email: String): String? {
return if (!email.isValidEmail()) {
"No Email Found"
} else email
}}
Bu erda, EmailAdapter-da biz fromJson funksiyasi oldida EmailCheck annotatsiyasini ishlatdik.
Biz uni obyektga o’tkazish uchun tahlil qilayotgan JSON elektron pochta emasligini tekshiramiz.
Shu usulda, biz ham toJson elektron pochta parametrini EmailCheck annotatsiyasii qo’yildi, bu
faqat EmailCheck izohli kalitlarga ruxsat berilganligini bildiradi.
Biz Moshi obyektini KotlinJsonAdapterFactory deb nomlangan yangi factoryga bilan
o’zgartiramiz.
val moshi = Moshi.Builder()
.add(EmailAdapter())
.add(KotlinJsonAdapterFactory())
.build()
Va endi, user obyektini yarataylik.
val user = User(Name("Himanshu", "Singh"), email = "00")
jsonAdapter.toJson funksiyasi ishlaydi va biz javob sifatida quyidagilarni olamiz,
User(name=Name(firstName=Himanshu, lastName=Singh), email=No Email Found)
Email maydonida biz elektron pochta topilmasligini ko’ramiz, chunki elektron pochta haqiqiy
emas. Shunday qilib, biz alohida maydonlar uchun adapterlarni yaratishimiz va unga ma’lum
shartlarni qo’yishimiz mumkin.
Moshi-ni ro’yxat bilan ishlatish(Collections)
Ushbu bo’limda biz ro’yxatni String-ga, so’ngra String-ni ro’yxatga qanday o’zgartirishni
o’rganamiz.
Misol ko’rib chiqaylik, bu yerda biz serverdan obyektlar ro’yxatini olamiz va uni ilovamizning
xohishiga ko’ra saqlashimiz kerak.
Aytaylik, bizda String toifasidagi ro’yxat bor,
val names = listOf("Himanshu","Amit", "Ali", "Sumit")
va endi biz ma’lumotimizni turini sozlashimiz kerak,
val type = Types.newParameterizedType(List::class.java, String::class.java)
Bu yerda bizda String ma’lumotlari ro’yxati mavjud, shuning uchun String::class elementlarning
turini aniqlash uchun class sifatida talab qilinadi va List — aylantirilishi kerak bo’lgan
ma’lumotlar turi.
Keyin bu turni ishlatish uchun biz uni Moshi adapteri bilan ishlatamiz, masalan:
val adapter = moshi.adapter<List<String>>(type)val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
Endi ma’lumotlar ro’yxatini String-ga aylantirish uchun biz toJsondan foydalanamiz,
val namesInString: String = adapter.toJson(names)
Bu ro’yxat ma’lumotlarini String-ga moslashtiradi va agar xohlasak, kesh xotirada saqlashimiz
mumkin.
Endi, agar biz String ni ro’yxatga o’tkazishni xohlasak, yaratgan adapterimizni ishlatamiz va
fromJson moshi yordamida uni quyidagicha o’zgartiramiz:
val allNames: List<String>? = adapter.fromJson(namesInString)
Moshi-ni retrofit bilan ishlatish
Ushbu bo’limda biz Android-da konvertor sifatida Moshi-dan foydalanib API -ga qanday
murojaat qilishimiz mumkinligi haqida gapiramiz.
https://jsonplaceholder.typicode.com/posts/1
Retrofit yordamida bitta postni olish uchun. Shunday qilib, birinchi navbatda, uni bosqichmabosqich ko’rib chiqaylik.
1-qadam
Biz avval build.gradle-ga retrofit hamda moshi kutubxonalarini qo’shamiz, masalan:
implementation "com.squareup.retrofit2:retrofit:2.8.1" implementation
"com.squareup.retrofit2:converter-moshi:2.6.2"
2-qadam
Biz API-dan oladigan response-da keladigan JSON format uchun PostsResponse deb nomlangan
class yaratamiz. JSON formati quyidagicha ko’rinishda:
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "tiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
Ushbu JSON format bo’yicha yaratilgan class quyidagicha bo’ladi:
data class PostsResponse(@Json(name = "id")
val id: Int = 0,
@Json(name = "title")
val title: String = "",
@Json(name = "body")
val body: String = "",
@Json(name = "userId")
val userId: Int = 0)
Bu yerda biz classda barcha maydonlarga @Json ishlatganimizni ko’rishingiz mumkin.
Biz @Jsondan foydalanganimiz uchun biz class konstruktoridagi o’zgaruvchilarga har qanday
nom bera olamiz va JSON class maydonlariga moslashtiriladi, chunki bu yerda annotatsiya
ishlatilgan.
3-qadam
Endi biz API ga so’rov yuborish uchun interfeys yaratamiz. Biz uni APIService deb ataymiz:
interface APIService {
@GET("/posts/1")
fun getSinglePost(): Call<PostsResponse>
}
Bunda getSinglePost deb nomlangan bitta funksiyaga bo’ladi va URLdagi yagona xabarni
qaytaradi.
4-qadam
Endi, Retrofit-ni o’rnatish uchun biz avval Moshi obyektini yaratamiz, masalan:
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
va keyin biz Retrofit obyektini yaratamiz,
val retrofit = Retrofit.Builder()
.baseUrl("https://jsonplaceholder.typicode.com/")
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
Bu yerda biz Moshi konvertoriga Moshi obyektini berdik.
Va KotlinJsonAdapterFactory-ni qo’llab-quvvatlash uchun qo’shimcha ravishda kutubxona
qo’shish kerak,
implementation "com.squareup.moshi:moshi-kotlin:1.9.3"
5-qadam
Biz hozir API ga so’rov yuboramiz, masalan:
retrofit.create(APIService::class.java).getSinglePost().enqueue(object : Callback<PostsResponse> {
override fun onFailure(call: Call<PostsResponse>, t: Throwable) {
Log.d("MainActivity", t.localizedMessage)
}override fun onResponse(call: Call<PostsResponse>, response: Response<PostsResponse>) {
Log.d("MainActivity", response.body().toString())
}})
Va ilovani ishga tushirishdan oldin, Manifest fayliga Internetga ruxsat berishni unutmang.
Endi, agar biz ilovani ishga tushirsak, quyidagilarni olamiz:
PostsResponse(id=1, title=sunt aut facere repellat provident occaecati excepturi optio reprehenderit,
body=quia et suscipit
suscipit recusandae consequuntur expedita et cum
reprehenderit molestiae ut ut quas totam
nostrum rerum est autem sunt rem eveniet architecto, userId=1)
API ga yuborilgan so’rovga muvaffaqiyatli javob keldi.
Qo’shimcha
Aytaylik, agar biz API javobida sarlavhani e’tiborsiz qoldirishni istasak, biz obyekt modelni
o’zgartiramiz,
data class PostsResponse(@Json(name = "id")
val id: Int = 0,
@Json(name = "title")
@Transient
val title: String = "",
@Json(name = "body")
val body: String = "",
@Json(name = "userId")
val userId: Int = 0)
Bu yerda biz Transient anotatsiyasini qo’shganimizni ko’rishingiz mumkin, u maydon nomini
e’tiborsiz qoldiradi va konsolda quyidagicha ko’rinishida obyekt ma’lumotlari ko’rinadi:
PostsResponse(id=1, title=, body=quia et suscipit
suscipit recusandae consequuntur expedita et cum
reprehenderit molestiae ut ut quas totam
nostrum rerum est autem sunt rem eveniet architecto, userId=1)
Bu yerda sarlavha maydoni bo’sh kelmoqda.
Xulosa
•
Moshi juda yengil parse qilish xususiyatiga ega.
•
U xuddi shu GSON mexanizmlaridan foydalanadi.
•
Biz @Json annotatsiyasi orqali maxsus maydon nomlarini qo’shishimiz mumkin.
0
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )