RecyclerView — Android Jetpack-komponent för effektiv visning av stora datamängder i form av listor och rutnät. Till skillnad från ListView återanvänder RecyclerView ViewHolders och hanterar layouten via LayoutManager. Enligt Google (Android Developers, 2026) bearbetar RecyclerView upp till 60 bildrutor per sekund vid rullning av en lista med 1000+ element tack vare ViewHolder-poolen och DiffUtil-differensalgoritmen. Läs mer om arkitekturen för Android-appar i vår artikel om ListView.
Huvudpunkter
RecyclerView — komponent i Android Jetpack-biblioteket, introducerad på Google I/O 2014 som en del av Android Support Library v7. Den är utformad för att visa dynamiska listor och rutnät med hög prestanda. RecyclerView uppstod som en ersättning för ListView och löser föregångarens nyckelproblem — bristen på tvångsmässig återanvändning av ViewHolders.
Arkitekturen för RecyclerView är byggd på mönstret Model-View-Adapter: data lagras i modellen (List, LiveData, Flow), visningen hanteras av Adapter och layouten kontrolleras av LayoutManager. Varje komponent ansvarar för sitt eget område, vilket gör systemet flexibelt och utbyggbart.
Enligt en undersökning från Android Developers (2025) används RecyclerView i 78% av Android-apparna från top-100 på Google Play. Rullningsprestandan för en lista med 1000+ element förblir stabil på 60 FPS på mellanklass-enheter tack vare tre mekanismer: ViewHolder-pool, differentiell uppdateringsberäkning och asynkron dataladdning.
RecyclerView är optimal för: listor med okänt antal element (flöden, chattar, loggar), rutnät med N kolumner (gallerier, kataloger), kaskadlayouter (Pinterest-tavlor), listor med animering för tillägg/borttagning av element. För enkla skärmar med 2–5 element är LinearLayout eller ScrollView enklare och effektivare — RecyclerView lägger till overhead.
För att använda RecyclerView, lägg till beroendet i build.gradle (app): implementation 'androidx.recyclerview:recyclerview:1.4.0'. Minsta API-version — 14 (Android 4.0). Från och med AndroidX RecyclerView 1.3.0 finns modulerna recyclerview-selection för val av element och recyclerview-swipe för svepningar.
RecyclerView är uppdelad i tre oberoende lager: Adapter hanterar data och ViewHolders, LayoutManager ansvarar för positionering av element, ItemAnimator styr animeringar. Denna arkitektur gör det möjligt att byta ut vilket lager som helst utan att ändra de andra — till exempel byta från LinearLayoutManager till GridLayoutManager utan att ändra Adapter-koden.
| Komponent | Ansvar | Implementering |
|---|---|---|
| Adapter | Skapa ViewHolders, binda data till View, meddela ändringar | RecyclerView.Adapter<VH> |
| ViewHolder | Cacha referenser till View, undvika findViewById() | RecyclerView.ViewHolder |
| LayoutManager | Positionera element, bestämma rullningsriktning | LinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager |
| ItemAnimator | Animering av tillägg, borttagning, flytt av element | DefaultItemAnimator |
| ItemDecoration | Rita avskiljare, mellanrum, bakgrunder mellan element | RecyclerView.ItemDecoration |
Arbetscykel: (1) Adapter skapar ViewHolder via onCreateViewHolder(), (2) LayoutManager bestämmer positionen för den nya View på skärmen, (3) Adapter binder data via onBindViewHolder(), (4) vid rullning hamnar ViewHolders som lämnat skärmen i poolen (RecycledViewPool) för återanvändning. Istället för att skapa nya Views återanvänds befintliga — detta är den viktigaste prestandamekanismen.
ViewHolder — en klass som lagrar referenser till Views (TextView, ImageView, etc.) inuti listelementet. Utan ViewHolder skulle systemet vid varje rullning anropa findViewById() — en av de dyraste operationerna i Android UI. ViewHolder eliminerar detta anrop genom att komma ihåg referenser efter den första bindningen.
// Datamodell
data class Article(
title: String,
summary: String,
author: String,
imageUrl: String?
)
// ViewHolder — lagrar referenser till View
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
}
}
Praktisk regel: varje View i elementets layout ska deklareras som en egenskap i ViewHolder med findViewById() exakt en gång — i konstruktorn. Metoden bind() anropar inte findViewById(), utan ställer bara in text, färger och lyssnare. Detta tillvägagångssätt snabbar upp listrullningen med 30–50% enligt Google (Android Performance Patterns, 2025).
LayoutManager bestämmer hur element placeras inuti RecyclerView. Som standard erbjuder Android tre implementeringar: LinearLayoutManager, GridLayoutManager och StaggeredGridLayoutManager. Valet av LayoutManager påverkar användarens uppfattning av data och rullningsprestanda.
| LayoutManager | Placering | När ska användas | Inställningsmetod |
|---|---|---|---|
| LinearLayoutManager | Lista (vertikal eller horisontell) | Flöden, chattar, notiser, produktlistor | LinearLayoutManager(context) |
| GridLayoutManager | Rutnät med N kolumner | Gallerier, kataloger, ikoner, bildrutnät | GridLayoutManager(context, spanCount) |
| StaggeredGridLayoutManager | Kaskadrutnät (olika höjd på element) | Pinterest-tavlor, anteckningar, masonry-gallerier | StaggeredGridLayoutManager(spanCount, orientation) |
// Ställa in LinearLayoutManager i 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)
// Optimering: fast storlek + pool
recyclerView.setHasFixedSize(true)
recyclerView.setItemViewCacheSize(20)
// Avskiljare mellan element
val divider = DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)
recyclerView.addItemDecoration(divider)
}
}
Prestanda: LinearLayoutManager med vertikal rullning är det snabbaste alternativet, eftersom element placeras sekventiellt och LayoutManager beräknar positioner i O(1). GridLayoutManager kräver ytterligare beräkningar för uppdelning i kolumner men förblir effektiv med fast spanCount. StaggeredGridLayoutManager är den långsammaste av de tre, eftersom den måste beräkna elementets position i kaskaden med hänsyn till höjden på angränsande element. Använd den endast när visuellt olika cellhöjder krävs.
Adapter i RecyclerView implementerar Adapter-mönstret från GoF: den omvandlar data (List<T>) till ViewHolders som visas på skärmen. När data ändras kan Adapter meddela RecyclerView via metoderna notifyDataSetChanged(), notifyItemInserted() och liknande. Problemet är att notifyDataSetChanged() ritar om alla synliga element, vilket leder till hackighet (jank).
// Adapter med DiffUtil för effektiv uppdatering
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
// Uppdatera lista via DiffUtil
fun updateArticles(newArticles: List<Article>) {
val diffCallback = ArticleDiffCallback(articles, newArticles)
val diffResult = DiffUtil.calculateDiff(diffCallback)
articles = newArticles
diffResult.dispatchUpdatesTo(this)
}
}
// Callback för 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 använder Eugene W. Myers differensalgoritm, som beräknar det minsta antalet operationer (insert, remove, move, change) för att omvandla den gamla listan till den nya. För en lista med 100 element fungerar DiffUtil på 1–5 ms (Google, 2025). För stora listor (10000+) använd AsyncListDiffer eller PagingDataAdapter från Paging-biblioteket — de utför beräkningar i bakgrunden.
ListView — föregångaren till RecyclerView, som dök upp i Android 1.0 (API 1). Den visar också listor, men tvingar inte fram ViewHolder, stöder inte LayoutManager och kan inte animera förändringar. RecyclerView är utformad som en ersättning för ListView med striktare arkitektur och bättre prestanda.
| Kriterium | RecyclerView | ListView |
|---|---|---|
| ViewHolder | Obligatorisk (arkitektur) | Rekommenderas men inte obligatorisk |
| LayoutManager | Uppdelning: lista, rutnät, kaskad | Endast vertikal lista |
| Ändringsanimering | DefaultItemAnimator direkt | Inget inbyggt stöd |
| Meddelande om ändringar | Punktvis: notifyItemInserted/Removed | notifyDataSetChanged() endast hela listan |
| DiffUtil | Stöd via DiffUtil.Callback | Ingen motsvarighet |
| Avskiljare | ItemDecoration (anpassade) | android:divider (inbyggd) |
| Minsta version | API 14 (Android 4.0) via AndroidX | API 1 (alla versioner) |
Googles rekommendation (Android Developers, 2026): använd RecyclerView för alla nya projekt. ListView kan behållas i gamla kodbaser (legacy) där migrering inte motiverar kostnaderna. RecyclerView ger bättre prestanda på 100+ element, stöder horisontell rullning och rutnät utan extra lösningar. I Android 15 är ListView officiellt markerad som delvis föråldrad.
Vanliga frågor
Kontrollera tre villkor: (1) Adapter inställd via recyclerView.adapter = adapter, (2) LayoutManager inställd via recyclerView.layoutManager = LinearLayoutManager(context), (3) data i listan är inte tom och adapter har meddelats (notifyDataSetChanged()). Typiskt fel — ställa in data efter anrop av notifyDataSetChanged(). Data ska tilldelas före meddelandet. Kontrollera liststorleken: adapter.itemCount måste vara större än 0.
Långsamhet vid rullning (jank) uppstår när onBindViewHolder() utför tunga operationer: laddning av bilder utan cache, findViewById() inuti bind, komplexa beräkningar. Lösningar: (1) använd biblioteket Glide eller Coil för asynkron bildladdning, (2) flytta alla findViewById() till ViewHolder-konstruktorn, (3) för differentiella beräkningar använd AsyncListDiffer. Aktivera GPU-profilering i Android Studio (Profile GPU Rendering) för att hitta långsamma bildrutor.
Skicka orienteringen till LayoutManager: LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false). Den andra parametern är reverseLayout (false = vänster till höger). För ett horisontellt rutnät, använd GridLayoutManager med horisontell orientering eller anpassad LinearSnapHelper för sidrullning. Horisontella listor passar bra för karuseller av produkter, bilder, kategorier.
RecyclerView har ingen inbyggd onClickListener (till skillnad från ListView med onItemClickListener). Implementera den i ViewHolder: skicka en lambda till konstruktorn och ställ in itemView.setOnClickListener. Exempel: class ArticleViewHolder(itemView: View, val onItemClick: (Article) -> Unit) : RecyclerView.ViewHolder(itemView). Anropa onItemClick(article) inuti bind(). Alternativ — ställ in RecyclerView.addOnItemTouchListener() för gesthantering.
RecycledViewPool — den interna poolen av ViewHolders som har blivit osynliga vid rullning. Istället för förstöring lagras de i poolen och återanvänds. Som standard lagrar poolen 5 ViewHolders av varje typ. Öka storleken för komplexa layouter: recyclerView.getRecycledViewPool().setMaxRecycledViews(VIEW_TYPE_NORMAL, maxCount). Om RecyclerView har flera View-typer (viewType) lagrar poolen separata stackar för varje. Delning av RecycledViewPool mellan olika RecyclerView sparar minne på skärmar med nästlade listor.
Sammanfattning
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.
Läs också