Adapter — bu nima, mobil ishlab chiqish uchun interfeyslarni o'zgartirish namunasi

Muallif: IT Sectr Nashr etilgan: 2026-02-18 O'qish vaqti: 10 daq

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 — mos kelmaydigan interfeyslarga ega ob'ektlarning birgalikda ishlashiga imkon beruvchi strukturaviy namuna
  • RecyclerView.Adapter — Android-da namunaning amalga oshirilishi, ma'lumotlarni ro'yxat uchun ViewHolder-ga o'zgartiradi
  • UITableViewDataSource — iOS-da Adapter va DataSource namunalarini birlashtiruvchi amalga oshirish
  • Object Adapter kompozitsiyadan foydalanadi: adapter moslashtirilayotgan ob'ektga havola saqlaydi
  • Class Adapter ko'p merosdan foydalanadi — faqat C++ da mumkin, Java/Swift/Kotlin da mavjud emas

Adapter namunasi nima?

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.

Kotlin
// 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.

Android-da Adapter: RecyclerView va ListAdapter

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.

Kotlin
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.

iOS-da Adapter: UITableView va DiffableDataSource

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.

Swift
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 vs Class Adapter

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.

XususiyatObject AdapterClass Adapter
MexanizmKompozitsiya (Adaptee ni o'z ichiga oladi)Meros (extends Adaptee)
MoslashuvchanlikYuqori — Adaptee runtime da o'zgartirilishi mumkinPast — Adaptee kompilyatsiya vaqtida aniqlangan
Bog'liqlikZaif (interfeys orqali)Kuchli (meros orqali)
Kichik sinflarni moslashtirishHa — Adaptee har qanday kichik sinf bo'lishi mumkinYo'q — faqat aniq super sinf
MavjudlikJava, 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.

Real loyihalarda Adapter misollari

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.

StsenariyAdapteeTargetAdapter
Eski auth kutubxonasini integratsiya qilishLegacyAuthLib (callback-based)AuthService (suspend)LegacyAuthAdapter
JSON ni yangi modelga moslashtirishGsonParserJsonParser (Kotlinx Serialization)GsonAdapter
Push xizmatlari uchun yagona interfeysFCM, APNs, Huawei PushPushService token registerPushServiceAdapter

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 tipik xatolar

Adapter amalga oshirishdagi xatolar ro'yxatlarning sekinlashishiga, xotira oqishiga va ma'lumotlarni yangilash xatolariga olib keladi. Uchta keng tarqalgan muammoni ko'rib chiqamiz.

onBindViewHolder da og'ir operatsiyalar

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.

DiffUtil / DiffableDataSource ga e'tibor bermaslik

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.

Adapterda og'ir ob'ektlarni saqlash

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 va Proxy o'rtasidagi farq nima?

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.

Nega RecyclerView.Adapter Adapter namunasining misolidir?

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 va Class Adapter o'rtasidagi farq nima?

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.

Qachon Adapter ni Facade o'rniga ishlatish kerak?

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.

Adapter ni interfeyssiz amalga oshirish mumkinmi?

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

  • Adapter — mos kelmaydigan Adaptee interfeysini oraliq sinf orqali Target ga o'zgartiruvchi strukturaviy namuna
  • RecyclerView.Adapter (Android) va UITableViewDataSource (iOS) — mobil ishlab chiqishda namunaning asosiy misollari
  • Object Adapter kompozitsiyadan foydalanadi; Class Adapter (faqat C++) — ko'p meros
  • ListAdapter + DiffUtil (Android) va DiffableDataSource (iOS) — avtomatik farq hisoblash va animatsiya bilan zamonaviy evolyutsiya
  • onBindViewHolder da og'ir operatsiyalar, DiffUtil ni e'tiborsiz qoldirish va adapterda resurslarni saqlash — keng tarqalgan xatolar
  • Adapter legacy kodni integratsiya qilish, formatlarni moslashtirish va turli amalga oshirishlarni birlashtirish uchun qo'llaniladi
  • Tavsiya: ro'yxat yangilanishlarini qo'lda boshqarish o'rniga ListAdapter/DiffableDataSource dan foydalaning

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.

Loyihani muhokama qilish

Shuningdek o'qing