Reinigen des Adaptercodes mit MergeAdapter

Sind Sie müde von den überlasteten und komplexen Adaptern in Ihrem Projekt wie im Bild unten? Möchten Sie jedes Mal, wenn Sie einen neuen Zelltyp hinzufügen, den Adapter für RecyclerView neu schreiben, damit der Code leichter lesbar ist? Es gibt viele Ansätze. In den meisten Fällen wird empfohlen, den Delegatenadapter-Ansatz oder beispielsweise eine Bibliothek zum dynamischen Erstellen von Listen mit verschiedenen Arten von Ansichten wie einem Groupie zu verwenden, mit denen Sie sich in diesem Artikel vertraut machen können . Aber heute werden wir über eine neue Klasse sprechen, die dabei hilft, die Logik Ihres Adapters für verschiedene Zellen zu kapseln und dabei die SOLID-Prinzipien einzuhalten.



Bild



MergeAdapter ist eine neue Klasse, die in recyclerview eingeführt wurde : 1.2.0-alpha02 , mit der Sie mehrere Anzeigeadapter in einer einzigen RecyclerView kombinieren können. Auf diese Weise können Sie die Logik für jede Zelle in Ihrem Adapter kapseln und sie in Zukunft wiederverwenden.



Problem



Beginnen wir mit einem Beispiel. Angenommen, wir haben die Aufgabe, einen Feed mit zwei Datentypen anzuzeigen - einen Text mit einer Beschreibung und ein Bild. Der Code in der Methode onCreateViewHolder sieht im häufigsten Fall folgendermaßen aus:



override fun onCreateViewHolder(
    parent: ViewGroup, viewType: Int
): RecyclerView.ViewHolder? {
    val holder: RecyclerView.ViewHolder
    val inflater = LayoutInflater.from(parent.context)
    when (viewType) {
        TEXT_VIEW_TYPE -> {
            holder = TextViewHolder(
                inflater.inflate(R.layout.text_item, parent, false)
            )
        }
        IMAGE_VIEW_TYPE -> {
            holder = ImageViewHolder(
                inflater.inflate(R.layout.image_item, parent, false),
                imageClickListener
            )
        }
        else -> {
            throw IllegalArgumentException(
                "Can't create view holder from view type $viewType"
            )
        }
    }
    return holder
}


Warum ist das so schlimm? Der Nachteil dieser Implementierung verstößt gegen die Grundsätze von DRY und SOLID (Einzelverantwortung und offen geschlossen). Um dies sicherzustellen, müssen zwei Anforderungen hinzugefügt werden: Geben Sie einen neuen Datentyp (Kontrollkästchen) und ein weiteres Band ein, auf dem nur Kontrollkästchen und Bilder vorhanden sind.



Wir stehen vor der Wahl, denselben Adapter für das zweite Band zu verwenden oder ein neues zu erstellen? Unabhängig von der von uns gewählten Lösung müssen wir den Code ändern (ungefähr dasselbe, aber an verschiedenen Stellen). Es ist erforderlich, eine neue VIEW_TYPE, ViewHolder neue und Bearbeitungsmethoden hinzuzufügen : getItemViewType(), onCreateViewHolder() onBindViewHolder().



Wenn wir uns entscheiden, einen Adapter zu behalten, enden die Änderungen dort. Wenn jedoch in Zukunft neue Datentypen mit neuer Logik nur dem zweiten Feed hinzugefügt werden, verfügt der erste über zusätzliche Funktionen und muss ebenfalls getestet werden, obwohl er sich nicht geändert hat.



Wenn wir uns entscheiden, einen neuen Adapter zu erstellen, wird es viel doppelten Code geben.



Entscheidung



Mit der neuen MergeAdapter-Klasse können Sie verschiedene Adapter für verschiedene Zelltypen kombinieren. Ein sehr häufiger Anwendungsfall besteht beispielsweise darin, einen Spinner anzuzeigen, während Daten in den Feed geladen werden, und wenn plötzlich ein Ladefehler auftritt, eine Zelle mit einem Fehler am Ende des Feeds anzuzeigen.



Bild



Die Lösung für dieses Problem kann die Verwendung von MergeAdapter sein. Angenommen, wir haben 3 Adapter:




val firstAdapter: FirstAdapter = …
val secondAdapter: SecondAdapter = …
val thirdAdapter: ThirdAdapter = …val mergeAdapter = MergeAdapter(firstAdapter, secondAdapter, thirdAdapter)
recyclerView.adapter = mergeAdapter


In RecyclerView werden die Elemente jedes Adapters nacheinander in derselben Reihenfolge angezeigt, in der sie an den Konstruktor übergeben wurden. Mit verschiedenen Adaptern können Sie die Logik für verschiedene Zellen in der Liste trennen. Wenn Sie beispielsweise der Liste einen Titel hinzufügen müssen, müssen Sie diese Logik nicht im Adapter implementieren, der für die Anzeige des Hauptinhalts in der Liste verantwortlich ist. Sie können die Adapter für verschiedene Zelltypen trennen. Dieser Ansatz hilft, Logik zu kapseln und sie in Zukunft für verschiedene Bildschirme wiederzuverwenden.



Bild



Zeigen Sie den Download in der Kopfzeile oder am Ende der Liste an.



Um den Download-Status oben oder unten in der Liste anzuzeigen, müssen Sie jeweils Adapter hinzufügen:



val mergeAdapter = MergeAdapter(headerAdapter, listAdapter, footerAdapter)
recyclerView.adapter = mergeAdapter


Die obere und die untere Zelle verwenden dasselbe Layout, denselben ViewHolder und dieselbe UI-Logik (Ladestatus anzeigen und ausblenden). Im Allgemeinen würde es ausreichen, zwei Instanzen desselben Adapters oben und unten in der Liste zu verwenden. Ein Beispiel finden Sie hier oder hier .



Kurz gesagt, auf so einfache Weise können Sie den Code Ihres Projekts verbessern, wenn Sie einen komplexen Adapter mit verschiedenen Zelltypen verwenden.



Hat dir der Artikel gefallen? Vergessen Sie nicht, sich uns bei Telegram anzuschließen , und auf der AndroidSchool.ru- Plattform werden nützliche Materialien für Android-Entwickler und moderne Tutorials veröffentlicht.



All Articles