Adapter — vad är det, mönster för gränssnittsomvandling för mobilutveckling

Författare: IT Sectr Publicerad: 2026-02-18 Lästid: 10 min

Adapter — är ett strukturellt designmönster som omvandlar gränssnittet för en klass till ett annat gränssnitt som klienten förväntar sig. Inom mobilutveckling används Adapter oftast i RecyclerView.Adapter för Android och UITableViewDataSource för iOS. Enligt data från Google I/O (2024) används RecyclerView i 95% av Android-appar för att visa listor, och varje kräver sin egen Adapter-implementering.

Huvudpunkter

  • Adapter — strukturellt mönster som gör att objekt med inkompatibla gränssnitt kan arbeta tillsammans
  • RecyclerView.Adapter — implementering av mönstret i Android, omvandlar data till ViewHolder för listan
  • UITableViewDataSource — implementering i iOS som kombinerar mönstren Adapter och DataSource
  • Object Adapter använder komposition: adaptern innehåller en referens till det anpassade objektet
  • Class Adapter använder multipelt arv — endast möjligt i C++, inte tillgängligt i Java/Swift/Kotlin

Vad är Adapter-mönstret?

Adapter — strukturellt mönster som löser problemet med inkompatibla gränssnitt. Det lindar in ett objekt (Adaptee) i en klass (Adapter) med det gränssnitt som klienten förväntar sig (Target). Klienten arbetar med Target, utan att veta om Adaptee:s existens. Detta är en variant av Wrapper-mönstret.

Kotlin
// Befintlig klass med inkompatibelt gränssnitt
class LegacyAuthApi {
    fun loginWithToken(token: String): Map {
        return mapOf("status" to "ok", "user_id" to 42)
    }
}

// Målgränssnitt (vad klienten förväntar sig)
interface AuthService {
    suspend fun login(credentials: Credentials): Result
}

// Adapter — omvandlar LegacyAuthApi till AuthService
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 omvandlar anropet login(credentials) till loginWithToken(token) för det gamla API:et. Klienten (ViewModel) arbetar via AuthService-gränssnittet och vet inte om det under ligger den senaste Firebase Auth eller ett tio år gammalt API. Detta gör det möjligt att byta implementeringar utan att ändra klientkoden.

Adapter i Android: RecyclerView och ListAdapter

RecyclerView.Adapter — den vanligaste implementeringen av Adapter-mönstret i Android. Det omvandlar data (en lista av objekt) till ViewHolders som RecyclerView visar på skärmen. Med tillkomsten av ListAdapter (Android Architecture Components) fick mönstret inbyggt stöd för diff-beräkning för animering av förändringar.

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 använder ListAdapter med DiffUtil för effektiv omritning av listan. När data uppdateras beräknar DiffCallback skillnaden mellan den gamla och nya listan, och RecyclerView animerar endast de ändrade elementen — utan att rita om hela listan. Detta är en viktig fördel jämfört med äldre ListView som krävde manuell notifyDataSetChanged().

Adapter i iOS: UITableView och DiffableDataSource

UITableViewDataSource — är både Adapter- och DataSource-mönstret. Det omvandlar modelldata till tabellceller. Från och med iOS 13 introducerade Apple DiffableDataSource — en modern ersättning som, liksom ListAdapter i Android, automatiskt beräknar förändringar och animerar uppdateringar.

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
    }
}

// Modern version: 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 med DiffableDataSource animerar automatiskt förändringar vid uppdatering av data: element visas, försvinner eller flyttas med mjuka animationer. iOS DiffableDataSource och Android ListAdapter löser samma uppgift med olika API:er, men med samma logik — diff-beräkning + automatisk animering.

Object Adapter vs Class Adapter

Object Adapter använder komposition: adaptern innehåller en referens till Adaptee-objektet och delegerar anrop till det. Class Adapter använder arv: adaptern ärver Adaptee och implementerar samtidigt målgränssnittet. I Java, Swift och Kotlin är Class Adapter omöjligt på grund av avsaknaden av multipelt arv — endast Object Adapter återstår.

EgenskapObject AdapterClass Adapter
MekanismKomposition (innehåller Adaptee)Arv (extends Adaptee)
FlexibilitetHögre — Adaptee kan ändras under körningLägre — Adaptee är fast vid kompilering
KopplingSvag (via gränssnitt)Stark (via arv)
Anpassning av underklasserJa — Adaptee kan vara vilken underklass som helstNej — endast konkret superklass
TillgänglighetJava, Kotlin, Swift, C++, C#Endast språk med multipelt arv (C++)

Inom mobilutveckling används endast Object Adapter. RecyclerView.Adapter innehåller referenser till data och LayoutInflater, UITableViewDataSource innehåller en array av element. Komposition gör koden mer flexibel och testbar jämfört med arv.

Exempel på Adapter i verkliga projekt

Adapter tillämpas inte bara för listor. Låt oss titta på tre scenarier från mobilutvecklingspraktiken där mönstret löser problemet med integrering av inkompatibla komponenter.

ScenarioAdapteeTargetAdapter
Integrering av gammalt auth-bibliotekLegacyAuthLib (callback-based)AuthService (suspend)LegacyAuthAdapter
Anpassning av JSON till ny modellGsonParserJsonParser (Kotlinx Serialization)GsonAdapter
Enhetligt gränssnitt för push-tjänsterFCM, APNs, Huawei PushPushService token registerPushServiceAdapter

Varje Adapter inkapslar transformationslogiken: GsonAdapter översätter en JSON-sträng till ett objekt via @SerializedName, PushServiceAdapter abstraherar token-registrering för olika plattformar. Klienten (affärslogik) arbetar med ett enhetligt gränssnitt och är inte beroende av en specifik implementering.

Vanliga misstag vid implementering av Adapter

Misstag vid implementering av Adapter leder till långsamma listor, minnesläckor och buggar med datauppdateringar. Låt oss analysera tre vanliga problem.

Tunga operationer i onBindViewHolder

onBindViewHolder anropas för varje cell vid scrollning. Skapa objekt, JSON-tolkning eller databasfrågor i denna metod leder till hugg i listan (frame drops). Lösning: utför alla tunga beräkningar i förväg och skicka färdiga data till adaptern. För bilder, använd bibliotek med cachning — Glide, Coil, Kingfisher.

Ignorera DiffUtil / DiffableDataSource

Att anropa notifyDataSetChanged() vid varje uppdatering ritar om hela listan, vilket orsakar flimmer och fokusförlust på inmatningsfält. Lösning: använd ListAdapter med DiffUtil i Android eller DiffableDataSource i iOS. Diff-beräkning tar <1 ms för listor upp till 1000 element och säkerställer mjuka animationer.

Lagra tunga objekt i adaptern

Adaptern lever lika länge som RecyclerView/UITableView. Lagra Bitmap eller stora arrayer i adaptern leder till minnesläckor vid konfigurationsändring (skärmrotation, temaväxling). Lösning: adaptern bör endast lagra lätta datamodeller (data class / struct) och ladda tunga resurser via ViewHolder vid behov.

Vanliga frågor

Vad är skillnaden mellan Adapter och Proxy?

Adapter omvandlar Adaptees gränssnitt till Targets gränssnitt — klienten får ett nytt sätt att interagera. Proxy ger samma gränssnitt som det ursprungliga objektet, men lägger till åtkomstkontroll, cachning eller lazy-initiering. Proxy ändrar inte gränssnittet, Adapter — ändrar.

Varför är RecyclerView.Adapter ett exempel på Adapter-mönstret?

RecyclerView.Adapter omvandlar data (t.ex. en lista av User) till ViewHolder som RecyclerView kan visa. RecyclerView förväntar sig ViewHolder, data är i formatet List<User> — Adapter anpassar det ena till det andra. Dessutom hanterar Adapter ViewHolders livscykel via återvinningspoolen, vilket förbättrar listans prestanda.

Vad är skillnaden mellan Object Adapter och Class Adapter?

Object Adapter använder komposition: innehåller en referens till Adaptee och delegerar anrop till det. Class Adapter använder multipelt arv: ärver Adaptee och implementerar Target. I Java, Kotlin och Swift är endast Object Adapter tillgängligt på grund av avsaknaden av multipelt klassarv. Class Adapter är endast möjligt i C++.

När ska man använda Adapter istället för Facade?

Adapter används när två befintliga klasser behöver samarbeta genom att omvandla gränssnittet för en av dem. Facade — när interaktionen med ett komplext delsystem behöver förenklas genom att tillhandahålla ett enkelt gränssnitt. Adapter — för kompatibilitet, Facade — för förenkling.

Kan man implementera Adapter utan gränssnitt?

Ja, med hjälp av slutningar (closures). Istället för ett gränssnitt med en metod kan en funktion skickas. Till exempel i Swift: let adapter = { (data: Data) -> [CellConfig] in /* omvandling */ }. Detta tillvägagångssätt kallas funktionell adapter. För 2+ metoder är dock protokoll/gränssnitt fortfarande att föredra — det gör kontraktet explicit.

Sammanfattning

  • Adapter — strukturellt mönster som omvandlar det inkompatibla Adaptee-gränssnittet till Target via en mellanliggande klass
  • RecyclerView.Adapter (Android) och UITableViewDataSource (iOS) — huvudexempel på mönstret inom mobilutveckling
  • Object Adapter använder komposition; Class Adapter (endast C++) — multipelt arv
  • ListAdapter + DiffUtil (Android) och DiffableDataSource (iOS) — moderna evolutioner med automatisk diff och animering
  • Tunga operationer i onBindViewHolder, ignorering av DiffUtil och lagring av resurser i adaptern — vanliga misstag
  • Adapter tillämpas för integrering av äldre kod, anpassning av format och sammanslagning av olika implementeringar
  • Rekommendation: använd ListAdapter/DiffableDataSource istället för manuell hantering av listuppdateringar

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också