Adapter — was ist das, das Schnittstellentransformations-Pattern für die mobile Entwicklung

Autor: IT Sectr Veröffentlicht: 2026-02-18 Lesezeit: 10 Min.

Adapter ist ein strukturelles Entwurfsmuster, das die Schnittstelle einer Klasse in eine andere, vom Client erwartete Schnittstelle umwandelt. In der mobilen Entwicklung wird Adapter am häufigsten in RecyclerView.Adapter für Android und UITableViewDataSource für iOS verwendet. Laut Google I/O (2024) wird RecyclerView in 95% der Android-Apps zur Anzeige von Listen verwendet, und jede benötigt eine eigene Adapter-Implementierung.

Wichtige Punkte

  • Adapter ist ein strukturelles Muster, das Objekten mit inkompatiblen Schnittstellen ermöglicht, zusammenzuarbeiten
  • RecyclerView.Adapter ist eine Implementierung des Patterns in Android, die Daten in ViewHolder für die Liste umwandelt
  • UITableViewDataSource ist eine Implementierung in iOS, die die Adapter- und DataSource-Patterns kombiniert
  • Object Adapter verwendet Komposition: der Adapter enthält eine Referenz auf das Adaptee-Objekt
  • Class Adapter verwendet Mehrfachvererbung — nur in C++ möglich, nicht in Java/Swift/Kotlin verfügbar

Was ist das Adapter-Pattern?

Adapter ist ein strukturelles Muster, das das Problem der Schnittstelleninkompatibilität löst. Es kapselt ein Objekt (Adaptee) in einer Klasse (Adapter) mit der vom Client erwarteten Schnittstelle (Target). Der Client arbeitet mit Target, ohne von der Existenz des Adaptee zu wissen. Dies ist eine Variante des Wrapper-Patterns.

Kotlin
// Vorhandene Klasse mit inkompatibler Schnittstelle
class LegacyAuthApi {
    fun loginWithToken(token: String): Map {
        return mapOf("status" to "ok", "user_id" to 42)
    }
}

// Zielschnittstelle (was der Client erwartet)
interface AuthService {
    suspend fun login(credentials: Credentials): Result
}

// Adapter — wandelt LegacyAuthApi in AuthService um
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 wandelt den login(credentials)-Aufruf in loginWithToken(token) für die alte API um. Der Client (ViewModel) arbeitet über die AuthService-Schnittstelle und weiß nicht, ob darunter das neueste Firebase Auth oder eine jahrzehntealte Legacy-API liegt. Dies ermöglicht den Austausch von Implementierungen ohne Änderung des Client-Codes.

Adapter in Android: RecyclerView und ListAdapter

RecyclerView.Adapter ist die häufigste Implementierung des Adapter-Patterns in Android. Es wandelt Daten (eine Liste von Objekten) in ViewHolder um, die RecyclerView auf dem Bildschirm anzeigt. Mit der Einführung von ListAdapter (Android Architecture Components) erhielt das Pattern eine integrierte Diff-Berechnungsunterstützung zum Animieren von Änderungen.

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 verwendet ListAdapter mit DiffUtil für effizientes Neuzeichnen der Liste. Wenn die Daten aktualisiert werden, berechnet DiffCallback den Unterschied zwischen der alten und neuen Liste, und RecyclerView animiert nur die geänderten Elemente — ohne die gesamte Liste neu zu zeichnen. Dies ist ein entscheidender Vorteil gegenüber der älteren ListView, die ein manuelles notifyDataSetChanged() erforderte.

Adapter in iOS: UITableView und DiffableDataSource

UITableViewDataSource ist gleichzeitig das Adapter-Pattern und das DataSource-Pattern. Es wandelt Modelldaten in Tabellenzellen um. Seit iOS 13 hat Apple DiffableDataSource eingeführt — einen modernen Ersatz, der wie ListAdapter in Android automatisch Änderungen berechnet und Aktualisierungen animiert.

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 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 mit DiffableDataSource animiert Änderungen automatisch, wenn Daten aktualisiert werden: Elemente erscheinen, verschwinden oder bewegen sich mit flüssigen Animationen. DiffableDataSource in iOS und ListAdapter in Android lösen dasselbe Problem mit unterschiedlichen APIs, aber derselben Logik — Diff-Berechnung + automatische Animation.

Object Adapter vs Class Adapter

Object Adapter verwendet Komposition: der Adapter enthält eine Referenz auf das Adaptee-Objekt und delegiert Aufrufe an es. Class Adapter verwendet Vererbung: der Adapter erbt von Adaptee und implementiert gleichzeitig die Zielschnittstelle. In Java, Swift und Kotlin ist Class Adapter aufgrund fehlender Mehrfachvererbung unmöglich — es bleibt nur Object Adapter.

EigenschaftObject AdapterClass Adapter
MechanismusKomposition (enthält Adaptee)Vererbung (erweitert Adaptee)
FlexibilitätHöher — Adaptee kann zur Laufzeit geändert werdenNiedriger — Adaptee ist zur Kompilierzeit festgelegt
KopplungSchwach (über Schnittstelle)Stark (über Vererbung)
Subklassen-AnpassungJa — Adaptee kann eine beliebige Subklasse seinNein — nur eine bestimmte Superklasse
VerfügbarkeitJava, Kotlin, Swift, C++, C#Nur Sprachen mit Mehrfachvererbung (C++)

In der mobilen Entwicklung wird nur Object Adapter verwendet. RecyclerView.Adapter enthält Referenzen auf Daten und LayoutInflater, UITableViewDataSource enthält ein Array von Elementen. Komposition macht den Code flexibler und testbarer im Vergleich zur Vererbung.

Adapter-Beispiele in echten Projekten

Adapter wird nicht nur für Listen verwendet. Betrachten wir drei Szenarien aus der mobilen Entwicklungspraxis, in denen das Pattern das Problem der Integration inkompatibler Komponenten löst.

SzenarioAdapteeTargetAdapter
Integration einer alten Auth-BibliothekLegacyAuthLib (callback-basiert)AuthService (suspend)LegacyAuthAdapter
JSON-Anpassung an ein neues ModellGsonParserJsonParser (Kotlinx Serialization)GsonAdapter
Einheitliche Schnittstelle für Push-DiensteFCM, APNs, Huawei PushPushService token registerPushServiceAdapter

Jeder Adapter kapselt die Konvertierungslogik: GsonAdapter übersetzt einen JSON-String über @SerializedName in ein Objekt, PushServiceAdapter abstrahiert die Token-Registrierung für verschiedene Plattformen. Der Client (Geschäftslogik) arbeitet mit einer einheitlichen Schnittstelle und ist nicht von der spezifischen Implementierung abhängig.

Häufige Fehler bei der Adapter-Implementierung

Fehler bei der Adapter-Implementierung führen zu langsamen Listen, Speicherlecks und Fehlern bei Datenaktualisierungen. Betrachten wir drei häufige Probleme.

Schwere Operationen in onBindViewHolder

onBindViewHolder wird für jede Zelle beim Scrollen aufgerufen. Objekterstellung, JSON-Parsing oder Datenbankaufrufe in dieser Methode führen zu Rucklern (Frame Drops). Lösung: alle schweren Berechnungen im Voraus durchführen und dem Adapter bereits aufbereitete Daten übergeben. Für Bilder Caching-Bibliotheken verwenden — Glide, Coil, Kingfisher.

Ignorieren von DiffUtil / DiffableDataSource

Der Aufruf von notifyDataSetChanged() bei jeder Aktualisierung zeichnet die gesamte Liste neu, was zu Flimmern und Fokusverlust bei Eingaben führt. Lösung: ListAdapter mit DiffUtil in Android oder DiffableDataSource in iOS verwenden. Die Diff-Berechnung dauert <1 ms für Listen mit bis zu 1000 Elementen und gewährleistet flüssige Animationen.

Speichern schwerer Objekte im Adapter

Der Adapter lebt so lange wie RecyclerView/UITableView. Das Speichern von Bitmaps oder großen Arrays im Adapter führt bei Konfigurationsänderungen (Bildschirmdrehung, Themenwechsel) zu Speicherlecks. Lösung: Der Adapter sollte nur leichte Datenmodelle (data class / struct) speichern und schwere Ressourcen bei Bedarf über ViewHolder laden.

Häufig gestellte Fragen

Was ist der Unterschied zwischen Adapter und Proxy?

Adapter wandelt die Adaptee-Schnittstelle in die Target-Schnittstelle um — der Client erhält eine neue Interaktionsmöglichkeit. Proxy bietet dieselbe Schnittstelle wie das ursprüngliche Objekt, fügt aber Zugriffskontrolle, Caching oder verzögerte Initialisierung hinzu. Proxy ändert die Schnittstelle nicht, Adapter schon.

Warum ist RecyclerView.Adapter ein Beispiel für das Adapter-Pattern?

RecyclerView.Adapter wandelt Daten (z.B. eine Liste von User) in einen ViewHolder um, den RecyclerView anzeigen kann. RecyclerView erwartet einen ViewHolder, die Daten liegen im List<User>-Format vor — der Adapter passt eines an das andere an. Zusätzlich verwaltet der Adapter den Lebenszyklus der ViewHolder über den Recycling-Pool und verbessert so die Listenleistung.

Was ist der Unterschied zwischen Object Adapter und Class Adapter?

Object Adapter verwendet Komposition: er enthält eine Referenz auf Adaptee und delegiert Aufrufe an ihn. Class Adapter verwendet Mehrfachvererbung: er erbt von Adaptee und implementiert Target. In Java, Kotlin und Swift ist nur Object Adapter verfügbar, da Mehrfachvererbung von Klassen fehlt. Class Adapter ist nur in C++ möglich.

Wann sollte man Adapter anstelle von Facade verwenden?

Adapter wird verwendet, wenn zwei vorhandene Klassen durch Konvertierung der Schnittstelle einer von ihnen zur Zusammenarbeit gebracht werden müssen. Facade wird verwendet, wenn die Interaktion mit einem komplexen Subsystem durch eine einfache Schnittstelle vereinfacht werden soll. Adapter dient der Kompatibilität, Facade der Vereinfachung.

Kann Adapter ohne Schnittstelle implementiert werden?

Ja, mit Closures. Anstelle einer Schnittstelle mit einer Methode kann eine Funktion übergeben werden. Zum Beispiel in Swift: let adapter = { (data: Data) -> [CellConfig] in /* Konvertierung */ }. Dieser Ansatz wird funktionaler Adapter genannt. Für 2+ Methoden bleibt jedoch ein Protokoll/Interface vorzuziehen — es macht den Vertrag explizit.

Zusammenfassung

  • Adapter ist ein strukturelles Muster, das eine inkompatible Adaptee-Schnittstelle über eine Zwischenklasse in Target umwandelt
  • RecyclerView.Adapter (Android) und UITableViewDataSource (iOS) sind die Hauptbeispiele des Patterns in der mobilen Entwicklung
  • Object Adapter verwendet Komposition; Class Adapter (nur C++) verwendet Mehrfachvererbung
  • ListAdapter + DiffUtil (Android) und DiffableDataSource (iOS) sind moderne Weiterentwicklungen mit automatischem Diff und Animation
  • Schwere Operationen in onBindViewHolder, Ignorieren von DiffUtil und Speichern von Ressourcen im Adapter sind häufige Fehler
  • Adapter wird zur Integration von Legacy-Code, zur Anpassung von Formaten und zur Vereinheitlichung verschiedener Implementierungen verwendet
  • Empfehlung: Verwenden Sie ListAdapter/DiffableDataSource anstelle der manuellen Listenaktualisierungsverwaltung

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch