RecyclerView — Android Jetpack-component voor het efficiënt weergeven van grote datasets in de vorm van lijsten en rasters. In tegenstelling tot ListView hergebruikt RecyclerView ViewHolders en beheert de lay-out via LayoutManager. Volgens Google (Android Developers, 2026) verwerkt RecyclerView tot 60 frames per seconde bij het scrollen van een lijst met 1000+ elementen dankzij de ViewHolder-pool en het DiffUtil-verschilalgoritme. Lees meer over de architectuur van Android-apps in ons artikel over ListView.
Belangrijkste
RecyclerView — component van de Android Jetpack-bibliotheek, geïntroduceerd op Google I/O 2014 als onderdeel van Android Support Library v7. Het is ontworpen voor het weergeven van dynamische lijsten en rasters met hoge prestaties. RecyclerView verscheen als vervanging voor ListView en lost het belangrijkste probleem van zijn voorganger op — het ontbreken van gedwongen hergebruik van ViewHolders.
De architectuur van RecyclerView is gebaseerd op het Model-View-Adapter-patroon: gegevens worden opgeslagen in het model (List, LiveData, Flow), weergave wordt beheerd door de Adapter en de lay-out wordt gecontroleerd door LayoutManager. Elk component is verantwoordelijk voor zijn eigen domein, wat het systeem flexibel en uitbreidbaar maakt.
Volgens een enquête van Android Developers (2025) wordt RecyclerView gebruikt in 78% van de Android-apps uit de top-100 van Google Play. De scrollprestaties van een lijst met 1000+ elementen blijven stabiel op 60 FPS op middenklasse apparaten dankzij drie mechanismen: ViewHolder-pool, differentiële updateberekening en asynchroon laden van gegevens.
RecyclerView is optimaal voor: lijsten met onbekend aantal elementen (feeds, chats, logs), rasters met N kolommen (galerijen, catalogi), cascadelay-outs (Pinterest-borden), lijsten met animatie voor toevoegen/verwijderen van elementen. Voor eenvoudige schermen met 2–5 elementen zijn LinearLayout of ScrollView eenvoudiger en efficiënter — RecyclerView voegt overhead toe.
Voeg de afhankelijkheid toe aan build.gradle (app) om RecyclerView te gebruiken: implementation 'androidx.recyclerview:recyclerview:1.4.0'. Minimale API-versie — 14 (Android 4.0). Sinds AndroidX RecyclerView 1.3.0 zijn de modules recyclerview-selection voor selectie van elementen en recyclerview-swipe voor swipe-bewegingen beschikbaar.
RecyclerView is verdeeld in drie onafhankelijke lagen: Adapter beheert gegevens en ViewHolders, LayoutManager zorgt voor positionering van elementen, ItemAnimator controleert animaties. Deze architectuur maakt het mogelijk om elke laag te vervangen zonder de andere te wijzigen — bijvoorbeeld overschakelen van LinearLayoutManager naar GridLayoutManager zonder de Adapter-code te wijzigen.
| Component | Verantwoordelijkheden | Implementatie |
|---|---|---|
| Adapter | Aanmaken van ViewHolders, binden van gegevens aan View, melden van wijzigingen | RecyclerView.Adapter<VH> |
| ViewHolder | Cachen van verwijzingen naar View, vermijden van findViewById() | RecyclerView.ViewHolder |
| LayoutManager | Positioneren van elementen, bepalen van scrollrichting | LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager |
| ItemAnimator | Animaties bij toevoegen, verwijderen, verplaatsen van elementen | DefaultItemAnimator |
| ItemDecoration | Tekenen van scheidingen, marges, achtergronden tussen elementen | RecyclerView.ItemDecoration |
Werkcyclus: (1) Adapter maakt ViewHolder aan via onCreateViewHolder(), (2) LayoutManager bepaalt de positie van de nieuwe View op het scherm, (3) Adapter bindt gegevens via onBindViewHolder(), (4) bij scrollen worden ViewHolders die buiten beeld zijn geraakt in de pool (RecycledViewPool) geplaatst voor hergebruik. In plaats van nieuwe Views te maken, worden bestaande hergebruikt — dit is het belangrijkste prestatiemechanisme.
ViewHolder — een klasse die verwijzingen naar Views (TextView, ImageView, enz.) binnen het lijstelement opslaat. Zonder ViewHolder zou het systeem bij elke scroll findViewById() aanroepen — een van de duurste bewerkingen in de Android UI. ViewHolder elimineert deze aanroep door verwijzingen na de eerste binding te onthouden.
// Gegevensmodel
data class Article(
title: String,
summary: String,
author: String,
imageUrl: String?
)
// ViewHolder — slaat verwijzingen naar View op
class ArticleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val titleText = itemView.findViewById<TextView>(R.id.tvTitle)
private val summaryText = itemView.findViewById<TextView>(R.id.tvSummary)
private val authorText = itemView.findViewById<TextView>(R.id.tvAuthor)
fun bind(article: Article) {
titleText.text = article.title
summaryText.text = article.summary
authorText.text = article.author
}
}
Praktische regel: elke View in de lay-out van het item moet precies één keer worden gedeclareerd als eigenschap van ViewHolder met findViewById() — in de constructor. De methode bind() roept findViewById() niet aan, maar stelt alleen tekst, kleuren en listeners in. Deze aanpak versnelt het scrollen van de lijst met 30–50% volgens Google (Android Performance Patterns, 2025).
LayoutManager bepaalt hoe elementen binnen RecyclerView worden geplaatst. Standaard biedt Android drie implementaties: LinearLayoutManager, GridLayoutManager en StaggeredGridLayoutManager. De keuze van LayoutManager beïnvloedt de perceptie van gegevens door de gebruiker en de scrollprestaties.
| LayoutManager | Plaatsing | Wanneer gebruiken | Instelmethode |
|---|---|---|---|
| LinearLayoutManager | Lijst (verticaal of horizontaal) | Feeds, chats, meldingen, productlijsten | LinearLayoutManager(context) |
| GridLayoutManager | Raster met N kolommen | Galerijen, catalogi, pictogrammen, afbeeldingsraster | GridLayoutManager(context, spanCount) |
| StaggeredGridLayoutManager | Cascaderaster (verschillende hoogte van elementen) | Pinterest-borden, notities, masonry-galerijen | StaggeredGridLayoutManager(spanCount, orientation) |
// LinearLayoutManager instellen in Fragment
class ArticleListFragment : Fragment() {
private lateinit var binding: FragmentArticleListBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val recyclerView = binding.recyclerView
recyclerView.layoutManager = LinearLayoutManager(requireContext())
recyclerView.adapter = ArticleAdapter(articlesList)
// Optimalisatie: vaste grootte + pool
recyclerView.setHasFixedSize(true)
recyclerView.setItemViewCacheSize(20)
// Scheiding tussen elementen
val divider = DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)
recyclerView.addItemDecoration(divider)
}
}
Prestaties: LinearLayoutManager met verticaal scrollen is de snelste optie, omdat elementen sequentieel worden geplaatst en LayoutManager posities berekent in O(1). GridLayoutManager vereist extra berekeningen voor verdeling over kolommen, maar blijft efficiënt met een vaste spanCount. StaggeredGridLayoutManager is de langzaamste van de drie, omdat het de positie van het element in de cascade moet berekenen rekening houdend met de hoogte van naburige elementen. Gebruik het alleen wanneer visueel verschillende celhoogtes vereist zijn.
Adapter in RecyclerView implementeert het Adapter-patroon uit GoF: het zet gegevens (List<T>) om in ViewHolders die op het scherm worden weergegeven. Bij wijziging van gegevens kan Adapter RecyclerView op de hoogte stellen via methoden zoals notifyDataSetChanged(), notifyItemInserted() en soortgelijke. Het probleem is dat notifyDataSetChanged() alle zichtbare elementen opnieuw tekent, wat leidt tot schokkerigheid (jank).
// Adapter met DiffUtil voor efficiënte updates
class ArticleAdapter : RecyclerView.Adapter<ArticleViewHolder>() {
private var articles: List<Article> = emptyList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_article, parent, false)
return ArticleViewHolder(view)
}
override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
holder.bind(articles[position])
}
override fun getItemCount(): Int = articles.size
// Lijst bijwerken via DiffUtil
fun updateArticles(newArticles: List<Article>) {
val diffCallback = ArticleDiffCallback(articles, newArticles)
val diffResult = DiffUtil.calculateDiff(diffCallback)
articles = newArticles
diffResult.dispatchUpdatesTo(this)
}
}
// Callback voor DiffUtil
class ArticleDiffCallback(
private val oldList: List<Article>,
private val newList: List<Article>
) : DiffUtil.Callback() {
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areItemsTheSame(oldPos: Int, newPos: Int): Boolean {
return oldList[oldPos].title == newList[newPos].title
}
override fun areContentsTheSame(oldPos: Int, newPos: Int): Boolean {
return oldList[oldPos] == newList[newPos]
}
}
DiffUtil maakt gebruik van het Eugene W. Myers' difference algorithm, dat het minimale aantal bewerkingen (insert, remove, move, change) berekent om de oude lijst om te zetten in de nieuwe. Voor een lijst van 100 elementen werkt DiffUtil in 1–5 ms (Google, 2025). Gebruik voor grote lijsten (10000+) AsyncListDiffer of PagingDataAdapter uit de Paging-bibliotheek — ze voeren berekeningen uit op de achtergrond.
ListView — de voorganger van RecyclerView, verschenen in Android 1.0 (API 1). Het geeft ook lijsten weer, maar dwingt ViewHolder niet af, ondersteunt geen LayoutManager en kan wijzigingen niet animeren. RecyclerView is ontworpen als vervanging voor ListView met een striktere architectuur en betere prestaties.
| Criterium | RecyclerView | ListView |
|---|---|---|
| ViewHolder | Verplicht (architectuur) | Aanbevolen, maar niet verplicht |
| LayoutManager | Verdeling: lijst, raster, cascade | Alleen verticale lijst |
| Animaties bij wijzigingen | DefaultItemAnimator uit de doos | Geen ingebouwde ondersteuning |
| Melden van wijzigingen | Puntsgewijs: notifyItemInserted/Removed | notifyDataSetChanged() alleen hele lijst |
| DiffUtil | Ondersteuning via DiffUtil.Callback | Geen equivalent |
| Scheidingen | ItemDecoration (aangepast) | android:divider (ingebouwd) |
| Minimale versie | API 14 (Android 4.0) via AndroidX | API 1 (alle versies) |
Google's aanbeveling (Android Developers, 2026): gebruik RecyclerView voor alle nieuwe projecten. ListView kan behouden blijven in oude codebases (legacy) waar migratie de kosten niet rechtvaardigt. RecyclerView biedt betere prestaties op 100+ elementen, ondersteunt horizontaal scrollen en rasters zonder extra oplossingen. In Android 15 is ListView officieel gemarkeerd als deels verouderd.
Veelgestelde vragen
Controleer drie voorwaarden: (1) Adapter ingesteld via recyclerView.adapter = adapter, (2) LayoutManager ingesteld via recyclerView.layoutManager = LinearLayoutManager(context), (3) gegevens in de lijst zijn niet leeg en adapter is op de hoogte gesteld (notifyDataSetChanged()). Typische fout — gegevens instellen na het aanroepen van notifyDataSetChanged(). Gegevens moeten worden toegewezen vóór de melding. Controleer de lijstgrootte: adapter.itemCount moet groter zijn dan 0.
Traagheid bij scrollen (jank) treedt op wanneer onBindViewHolder() zware bewerkingen uitvoert: laden van afbeeldingen zonder cache, findViewById() binnen bind, complexe berekeningen. Oplossingen: (1) gebruik Glide of Coil voor asynchroon laden van afbeeldingen, (2) verplaats alle findViewById() naar de ViewHolder-constructor, (3) gebruik AsyncListDiffer voor differentiële berekeningen. Schakel GPU-profilering in Android Studio (Profile GPU Rendering) in om trage frames te vinden.
Geef de oriëntatie door aan LayoutManager: LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false). De tweede parameter is reverseLayout (false = links naar rechts). Gebruik voor een horizontaal raster GridLayoutManager met horizontale oriëntatie of een aangepaste LinearSnapHelper voor paginascrolling. Horizontale lijsten zijn geschikt voor carrousels van producten, afbeeldingen, categorieën.
RecyclerView heeft geen ingebouwde onClickListener (in tegenstelling tot ListView met onItemClickListener). Implementeer het in ViewHolder: geef een lambda door aan de constructor en stel itemView.setOnClickListener in. Voorbeeld: class ArticleViewHolder(itemView: View, val onItemClick: (Article) -> Unit) : RecyclerView.ViewHolder(itemView). Roep onItemClick(article) aan binnen bind(). Alternatief — stel RecyclerView.addOnItemTouchListener() in voor gebarenherkenning.
RecycledViewPool — de interne pool van ViewHolders die onzichtbaar zijn geworden tijdens het scrollen. In plaats van vernietiging worden ze in de pool bewaard en hergebruikt. Standaard slaat de pool 5 ViewHolders van elk type op. Vergroot de grootte voor complexe lay-outs: recyclerView.getRecycledViewPool().setMaxRecycledViews(VIEW_TYPE_NORMAL, maxCount). Als RecyclerView meerdere View-types heeft (viewType), slaat de pool aparte stapels op voor elk type. Het delen van RecycledViewPool tussen verschillende Recyclerviews bespaart geheugen op schermen met geneste lijsten.
Samenvatting
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.
Lees ook