Adapter — wat is het, patroon voor het transformeren van interfaces voor mobiele ontwikkeling

Auteur: IT Sectr Gepubliceerd: 2026-02-18 Leestijd: 10 min

Adapter — is een structureel ontwerppatroon dat de interface van de ene klasse omzet naar een andere interface die de client verwacht. In mobiele ontwikkeling wordt Adapter meestal gebruikt in RecyclerView.Adapter voor Android en UITableViewDataSource voor iOS. Volgens Google I/O (2024) wordt RecyclerView gebruikt in 95% van de Android-apps voor het weergeven van lijsten, en elke vereist zijn eigen Adapter-implementatie.

Belangrijkste punten

  • Adapter — structureel patroon dat objecten met incompatibele interfaces samen laat werken
  • RecyclerView.Adapter — implementatie van het patroon in Android, zet gegevens om naar ViewHolder voor lijsten
  • UITableViewDataSource — implementatie in iOS die de patronen Adapter en DataSource combineert
  • Object Adapter gebruikt compositie: de adapter bevat een verwijzing naar het aangepaste object
  • Class Adapter gebruikt meervoudige overerving — alleen mogelijk in C++, niet beschikbaar in Java/Swift/Kotlin

Wat is het Adapter-patroon?

Adapter — een structureel patroon dat het probleem van incompatibele interfaces oplost. Het wikkelt een object (Adaptee) in een klasse (Adapter) met de interface die de client verwacht (Target). De client werkt met Target, zonder kennis van het bestaan van Adaptee. Dit is een variant van het Wrapper-patroon.

Kotlin
// Bestaande klasse met incompatibele interface
class LegacyAuthApi {
    fun loginWithToken(token: String): Map {
        return mapOf("status" to "ok", "user_id" to 42)
    }
}

// Doelinterface (wat de client verwacht)
interface AuthService {
    suspend fun login(credentials: Credentials): Result
}

// Adapter — zet LegacyAuthApi om naar 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 zet de aanroep login(credentials) om naar loginWithToken(token) voor de oude API. De client (ViewModel) werkt via de AuthService-interface en weet niet of er de nieuwste Firebase Auth of een tien jaar oude API onder zit. Dit maakt het mogelijk om implementaties te vervangen zonder de clientcode te wijzigen.

Adapter in Android: RecyclerView en ListAdapter

RecyclerView.Adapter — de meest voorkomende implementatie van het Adapter-patroon in Android. Het zet gegevens (een lijst van objecten) om in ViewHolders die RecyclerView op het scherm weergeeft. Met de komst van ListAdapter (Android Architecture Components) kreeg het patroon ingebouwde ondersteuning voor verschilberekening voor animatie van wijzigingen.

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 gebruikt ListAdapter met DiffUtil voor efficiënt hertekenen van de lijst. Wanneer gegevens worden bijgewerkt, berekent DiffCallback het verschil tussen de oude en nieuwe lijst, en RecyclerView animeert alleen de gewijzigde elementen — zonder de hele lijst te hertekenen. Dit is een belangrijk voordeel ten opzichte van de oudere ListView, die handmatig notifyDataSetChanged() vereiste.

Adapter in iOS: UITableView en DiffableDataSource

UITableViewDataSource — is zowel het Adapter- als het DataSource-patroon. Het zet modelgegevens om in tabelcellen. Vanaf iOS 13 introduceerde Apple DiffableDataSource — een moderne vervanging die, net als ListAdapter in Android, automatisch wijzigingen berekent en updates animeert.

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

// Moderne versie: 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 met DiffableDataSource animeert automatisch wijzigingen bij het bijwerken van gegevens: elementen verschijnen, verdwijnen of verplaatsen met vloeiende animaties. iOS DiffableDataSource en Android ListAdapter lossen dezelfde taak op met verschillende API's, maar met dezelfde logica — verschilberekening + automatische animatie.

Object Adapter vs Class Adapter

Object Adapter gebruikt compositie: de adapter bevat een verwijzing naar het Adaptee-object en delegeert aanroepen eraan. Class Adapter gebruikt overerving: de adapter erft Adaptee en implementeert tegelijkertijd de doelinterface. In Java, Swift en Kotlin is Class Adapter onmogelijk vanwege het ontbreken van meervoudige overerving — alleen Object Adapter blijft over.

KenmerkObject AdapterClass Adapter
MechanismeCompositie (bevat Adaptee)Overerving (extends Adaptee)
FlexibiliteitHoger — Adaptee kan tijdens runtime worden gewijzigdLager — Adaptee staat vast tijdens compilatie
KoppelingZwak (via interface)Sterk (via overerving)
Aanpassing van subklassenJa — Adaptee kan elke subklasse zijnNee — alleen concrete superklasse
BeschikbaarheidJava, Kotlin, Swift, C++, C#Alleen talen met meervoudige overerving (C++)

In mobiele ontwikkeling wordt alleen Object Adapter gebruikt. RecyclerView.Adapter bevat verwijzingen naar gegevens en LayoutInflater, UITableViewDataSource bevat een array van elementen. Compositie maakt de code flexibeler en beter testbaar in vergelijking met overerving.

Voorbeelden van Adapter in echte projecten

Adapter wordt niet alleen voor lijsten toegepast. Laten we drie scenario's uit de praktijk van mobiele ontwikkeling bekijken, waar het patroon het probleem van integratie van incompatibele componenten oplost.

ScenarioAdapteeTargetAdapter
Integratie van oude auth-bibliotheekLegacyAuthLib (callback-based)AuthService (suspend)LegacyAuthAdapter
Aanpassen JSON aan nieuw modelGsonParserJsonParser (Kotlinx Serialization)GsonAdapter
Universele interface voor push-dienstenFCM, APNs, Huawei PushPushService token registerPushServiceAdapter

Elke Adapter inkapselt de transformatielogica: GsonAdapter vertaalt een JSON-string naar een object via @SerializedName, PushServiceAdapter abstraheert tokenregistratie voor verschillende platforms. De client (businesslogica) werkt met een universele interface en is niet afhankelijk van een specifieke implementatie.

Veelvoorkomende fouten bij het implementeren van Adapter

Fouten in de implementatie van Adapter leiden tot trage lijsten, geheugenlekken en bugs met gegevensupdates. Laten we drie veelvoorkomende problemen bekijken.

Zware bewerkingen in onBindViewHolder

onBindViewHolder wordt voor elke cel aangeroepen tijdens het scrollen. Objecten maken, JSON-parsen of databasequery's in deze methode leiden tot haperende lijsten (frame drops). Oplossing: voer alle zware berekeningen van tevoren uit en geef de adapter al voorbereide gegevens. Gebruik voor afbeeldingen bibliotheken met caching — Glide, Coil, Kingfisher.

DiffUtil / DiffableDataSource negeren

Het aanroepen van notifyDataSetChanged() bij elke update hertekent de hele lijst, wat flikkering en focusverlies op invoervelden veroorzaakt. Oplossing: gebruik ListAdapter met DiffUtil in Android of DiffableDataSource in iOS. Verschilberekening duurt <1 ms voor lijsten tot 1000 elementen en zorgt voor vloeiende animaties.

Zware objecten opslaan in de adapter

De adapter leeft zo lang als RecyclerView/UITableView. Bitmap of grote arrays opslaan in de adapter leidt tot geheugenlekken bij configuratiewijzigingen (schermrotatie, themawissel). Oplossing: de adapter mag alleen lichte gegevensmodellen (data class / struct) opslaan, en zware bronnen laden via ViewHolder op aanvraag.

Veelgestelde vragen

Wat is het verschil tussen Adapter en Proxy?

Adapter zet de interface van Adaptee om naar de interface van Target — de client krijgt een nieuwe manier van interactie. Proxy biedt dezelfde interface als het originele object, maar voegt toegangscontrole, caching of luie initialisatie toe. Proxy verandert de interface niet, Adapter — wel.

Waarom is RecyclerView.Adapter een voorbeeld van het Adapter-patroon?

RecyclerView.Adapter zet gegevens (bijv. een lijst van User) om naar ViewHolder die RecyclerView kan weergeven. RecyclerView verwacht ViewHolder, de gegevens hebben de indeling List<User> — Adapter past het een aan het ander aan. Daarnaast beheert Adapter de levenscyclus van ViewHolder via de recycle-pool, wat de prestaties van de lijst verbetert.

Wat is het verschil tussen Object Adapter en Class Adapter?

Object Adapter gebruikt compositie: bevat een verwijzing naar Adaptee en delegeert aanroepen eraan. Class Adapter gebruikt meervoudige overerving: erft Adaptee en implementeert Target. In Java, Kotlin en Swift is alleen Object Adapter beschikbaar vanwege het ontbreken van meervoudige klasse-overerving. Class Adapter is alleen mogelijk in C++.

Wanneer Adapter gebruiken in plaats van Facade?

Adapter wordt gebruikt wanneer twee bestaande klassen moeten samenwerken door de interface van een van hen te transformeren. Facade — wanneer de interactie met een complex subsysteem vereenvoudigd moet worden door een eenvoudige interface te bieden. Adapter — voor compatibiliteit, Facade — voor vereenvoudiging.

Kan Adapter worden geïmplementeerd zonder interface?

Ja, met behulp van sluitingen (closures). In plaats van een interface met één methode kan een functie worden doorgegeven. Bijvoorbeeld in Swift: let adapter = { (data: Data) -> [CellConfig] in /* transformatie */ }. Deze benadering wordt functionele adapter genoemd. Voor 2+ methoden blijft echter protocol/interface de voorkeur — het maakt het contract expliciet.

Samenvatting

  • Adapter — structureel patroon dat de incompatibele Adaptee-interface omzet naar Target via een tussenliggende klasse
  • RecyclerView.Adapter (Android) en UITableViewDataSource (iOS) — belangrijkste voorbeelden van het patroon in mobiele ontwikkeling
  • Object Adapter gebruikt compositie; Class Adapter (alleen C++) — meervoudige overerving
  • ListAdapter + DiffUtil (Android) en DiffableDataSource (iOS) — moderne evoluties met automatische diff en animatie
  • Zware bewerkingen in onBindViewHolder, negeren van DiffUtil en opslaan van bronnen in de adapter — veelvoorkomende fouten
  • Adapter wordt toegepast voor integratie van legacy-code, aanpassen van formaten en unificatie van verschillende implementaties
  • Aanbeveling: gebruik ListAdapter/DiffableDataSource in plaats van handmatig beheer van lijstupdates

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook