Adapter — bu bir sinfning interfeysini mijoz kutgan boshqa interfeysga o'zgartiruvchi strukturaviy loyiha namunasidir. Mobil ishlab chiqishda Adapter eng ko'p Android uchun RecyclerView.Adapter va iOS uchun UITableViewDataSource da ishlatiladi. Google I/O (2024) ma'lumotlariga ko'ra, RecyclerView Android ilovalarining 95 foizida ro'yxatlarni ko'rsatish uchun ishlatiladi va har biri o'zining Adapter amalga oshirilishini talab qiladi.
Asosiy fikrlar
Adapter — interfeyslarning mos kelmasligi muammosini hal qiluvchi strukturaviy namuna. U bitta ob'ektni (Adaptee) mijoz kutgan interfeysga (Target) ega sinfga (Adapter) o'rab oladi. Mijoz Adaptee mavjudligidan bexabar Target bilan ishlaydi. Bu Wrapper namunasining bir turidir.
// Mos kelmaydigan interfeysga ega mavjud sinf
class LegacyAuthApi {
fun loginWithToken(token: String): Map {
return mapOf("status" to "ok", "user_id" to 42)
}
}
// Maqsadli interfeys (mijoz kutgan narsa)
interface AuthService {
suspend fun login(credentials: Credentials): Result
}
// Adapter — LegacyAuthApi ni AuthService ga o'zgartiradi
class LegacyAuthAdapter(
private val legacyApi: LegacyAuthApi
) : AuthService {
override suspend fun login(credentials: Credentials): Result {
val token = "${credentials.login}:${credentials.password}"
.encodeToByteArray().let { Base64.encodeToString(it) }
val response = legacyApi.loginWithToken(token)
return if (response["status"] == "ok") {
Result.success(User(response["user_id"] as Int))
} else {
Result.failure(AuthException("Login failed"))
}
}
}LegacyAuthAdapter eski API uchun login(credentials) chaqiruvini loginWithToken(token) ga o'zgartiradi. Mijoz (ViewModel) AuthService interfeysi orqali ishlaydi va uning ostida eng yangi Firebase Auth yoki o'n yillik eski API borligini bilmaydi. Bu mijoz kodini o'zgartirmasdan amalga oshirishlarni almashtirish imkonini beradi.
RecyclerView.Adapter — Android-da Adapter namunasining eng keng tarqalgan amalga oshirilishi. U ma'lumotlarni (ob'ektlar ro'yxatini) RecyclerView ekranda ko'rsatadigan ViewHolder-larga o'zgartiradi. ListAdapter (Android Architecture Components) paydo bo'lishi bilan namuna o'zgarishlar animatsiyasi uchun o'rnatilgan farqni hisoblash qo'llab-quvvatlashiga ega bo'ldi.
class UserAdapter(
private val onItemClick: (User) -> Unit
) : ListAdapter (DiffCallback()) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): UserViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_user, parent, false)
return UserViewHolder(view)
}
override fun onBindViewHolder(
holder: UserViewHolder,
position: Int
) {
holder.bind(getItem(position), onItemClick)
}
class UserViewHolder(itemView: View) :
RecyclerView.ViewHolder(itemView) {
private val tvName = itemView.findViewById(R.id.tvName)
fun bind(user: User, click: (User) -> Unit) {
tvName.text = user.name
itemView.setOnClickListener { click(user) }
}
}
private class DiffCallback : DiffUtil.ItemCallback () {
override fun areItemsTheSame(old: User, new: User) = old.id == new.id
override fun areContentsTheSame(old: User, new: User) = old == new
}
} UserAdapter samarali ro'yxatni qayta chizish uchun DiffUtil bilan ListAdapter-dan foydalanadi. Ma'lumotlar yangilanganda, DiffCallback eski va yangi ro'yxat o'rtasidagi farqni hisoblaydi va RecyclerView faqat o'zgartirilgan elementlarni animatsiya qiladi — butun ro'yxatni qayta chizmasdan. Bu qo'lda notifyDataSetChanged() talab qiladigan eski ListView dan asosiy ustunlikdir.
UITableViewDataSource — bir vaqtning o'zida ham Adapter, ham DataSource namunasidir. U model ma'lumotlarini jadval hujayralariga o'zgartiradi. iOS 13 dan boshlab Apple DiffableDataSource ni taqdim etdi — Android-dagi ListAdapter kabi o'zgarishlarni avtomatik hisoblaydigan va yangilanishlarni animatsiya qiladigan zamonaviy o'rnini bosuvchi.
class UserTableViewAdapter: NSObject, UITableViewDataSource {
var items: [User] = []
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
items.count
}
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(
withIdentifier: "UserCell", for: indexPath)
let user = items[indexPath.row]
cell.textLabel?.text = user.name
return cell
}
}
// Zamonaviy versiya: DiffableDataSource
enum Section { case main }
class ModernUserAdapter {
var dataSource: UITableViewDiffableDataSource<Section, User>!
func configure(for tableView: UITableView) {
dataSource = UITableViewDiffableDataSource(
tableView: tableView
) { tableView, indexPath, user in
let cell = tableView.dequeueReusableCell(
withIdentifier: "UserCell", for: indexPath)
cell.textLabel?.text = user.name
return cell
}
}
func update(with users: [User]) {
var snapshot = NSDiffableDataSourceSnapshot<Section, User>()
snapshot.appendSections([.main])
snapshot.appendItems(users)
dataSource.apply(snapshot, animatingDifferences: true)
}
}ModernUserAdapter DiffableDataSource bilan ma'lumotlar yangilanganda o'zgarishlarni avtomatik animatsiya qiladi: elementlar silliq animatsiyalar bilan paydo bo'ladi, yo'qoladi yoki harakatlanadi. iOS DiffableDataSource va Android ListAdapter bir xil vazifani turli API-lar bilan, ammo bir xil mantiq bilan hal qiladi — farqni hisoblash + avtomatik animatsiya.
Object Adapter kompozitsiyadan foydalanadi: adapter Adaptee ob'ektiga havola saqlaydi va unga chaqiruvlarni topshiradi. Class Adapter merosdan foydalanadi: adapter Adaptee dan meros oladi va bir vaqtning o'zida maqsadli interfeysni amalga oshiradi. Java, Swift va Kotlin da Class Adapter ko'p merosning yo'qligi sababli mumkin emas — faqat Object Adapter qoladi.
| Xususiyat | Object Adapter | Class Adapter |
|---|---|---|
| Mexanizm | Kompozitsiya (Adaptee ni o'z ichiga oladi) | Meros (extends Adaptee) |
| Moslashuvchanlik | Yuqori — Adaptee runtime da o'zgartirilishi mumkin | Past — Adaptee kompilyatsiya vaqtida aniqlangan |
| Bog'liqlik | Zaif (interfeys orqali) | Kuchli (meros orqali) |
| Kichik sinflarni moslashtirish | Ha — Adaptee har qanday kichik sinf bo'lishi mumkin | Yo'q — faqat aniq super sinf |
| Mavjudlik | Java, Kotlin, Swift, C++, C# | Faqat ko'p merosli tillar (C++) |
Mobil ishlab chiqishda faqat Object Adapter ishlatiladi. RecyclerView.Adapter ma'lumotlarga va LayoutInflater ga havolalarni saqlaydi, UITableViewDataSource elementlar massivini saqlaydi. Kompozitsiya kodni merosga nisbatan moslashuvchanroq va test qilinadigan qiladi.
Adapter nafaqat ro'yxatlar uchun qo'llaniladi. Mobil ishlab chiqish amaliyotidan uchta stsenariyni ko'rib chiqamiz, bu yerda namuna mos kelmaydigan komponentlarni integratsiya qilish muammosini hal qiladi.
| Stsenariy | Adaptee | Target | Adapter |
|---|---|---|---|
| Eski auth kutubxonasini integratsiya qilish | LegacyAuthLib (callback-based) | AuthService (suspend) | LegacyAuthAdapter |
| JSON ni yangi modelga moslashtirish | GsonParser | JsonParser (Kotlinx Serialization) | GsonAdapter |
| Push xizmatlari uchun yagona interfeys | FCM, APNs, Huawei Push | PushService token register | PushServiceAdapter |
Har bir Adapter o'zgartirish mantiqini inkapsulatsiya qiladi: GsonAdapter JSON qatorini @SerializedName orqali ob'ektga tarjima qiladi, PushServiceAdapter turli platformalar uchun tokenni ro'yxatdan o'tkazishni abstraksiya qiladi. Mijoz (biznes mantiq) yagona interfeys bilan ishlaydi va aniq amalga oshirishga bog'liq emas.
Adapter amalga oshirishdagi xatolar ro'yxatlarning sekinlashishiga, xotira oqishiga va ma'lumotlarni yangilash xatolariga olib keladi. Uchta keng tarqalgan muammoni ko'rib chiqamiz.
onBindViewHolder aylantirish paytida har bir hujayra uchun chaqiriladi. Bu usuldagi ob'ektlarni yaratish, JSON ni tahlil qilish yoki ma'lumotlar bazasi so'rovlari ro'yxatning silkinishiga (frame drops) olib keladi. Yechim: barcha og'ir hisob-kitoblarni oldindan bajarish, adapterga tayyor ma'lumotlarni uzatish. Rasmlar uchun keshlash kutubxonalaridan foydalaning — Glide, Coil, Kingfisher.
Har bir yangilanishda notifyDataSetChanged() ni chaqirish butun ro'yxatni qayta chizadi, miltillashga va kiritish maydonlarida fokus yo'qotilishiga olib keladi. Yechim: Android da DiffUtil bilan ListAdapter yoki iOS da DiffableDataSource dan foydalaning. Farqni hisoblash 1000 elementgacha bo'lgan ro'yxatlar uchun <1 ms davom etadi va silliq animatsiyalarni ta'minlaydi.
Adapter RecyclerView/UITableView qadar yashaydi. Adapterda Bitmap yoki katta massivlarni saqlash konfiguratsiya o'zgarishi (ekran aylanishi, mavzu o'zgarishi) paytida xotira oqishiga olib keladi. Yechim: adapter faqat engil ma'lumot modellarini (data class / struct) saqlashi kerak, og'ir resurslarni esa ViewHolder orqali talab bo'yicha yuklashi kerak.
Tez-tez so'raladigan savollar
Adapter Adaptee interfeysini Target interfeysiga o'zgartiradi — mijoz yangi o'zaro ta'sir usulini oladi. Proxy asl ob'ekt bilan bir xil interfeysni taqdim etadi, lekin kirish nazorati, keshlash yoki kechiktirilgan ishga tushirishni qo'shadi. Proxy interfeysni o'zgartirmaydi, Adapter — o'zgartiradi.
RecyclerView.Adapter ma'lumotlarni (masalan, User ro'yxatini) RecyclerView ko'rsatishi mumkin bo'lgan ViewHolder ga o'zgartiradi. RecyclerView ViewHolder kutadi, ma'lumotlar List<User> formatida — Adapter birini ikkinchisiga moslashtiradi. Qo'shimcha ravishda, Adapter ViewHolder ning hayot aylanishini qayta ishlatish hovuzi orqali boshqaradi, ro'yxat samaradorligini oshiradi.
Object Adapter kompozitsiyadan foydalanadi: Adaptee ga havola saqlaydi va unga chaqiruvlarni topshiradi. Class Adapter ko'p merosdan foydalanadi: Adaptee dan meros oladi va Target ni amalga oshiradi. Java, Kotlin va Swift da sinflarning ko'p merosi yo'qligi sababli faqat Object Adapter mavjud. Class Adapter faqat C++ da mumkin.
Adapter ikkita mavjud sinfni birgalikda ishlashga majbur qilish uchun, ulardan birining interfeysini o'zgartirganda ishlatiladi. Facade — murakkab quyi tizim bilan o'zaro ta'sirni soddalashtirish, oddiy interfeys taqdim etish uchun ishlatiladi. Adapter — moslik uchun, Facade — soddalashtirish uchun.
Ha, yopilishlar (closures) yordamida. Bitta usul bilan interfeys o'rniga funksiyani uzatish mumkin. Masalan, Swift da: let adapter = { (data: Data) -> [CellConfig] in /* o'zgartirish */ }. Bunday yondashuv functional adapter deb ataladi. Biroq 2+ usul uchun protokol/interfeys afzal — shartnomani aniq qiladi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.