RecyclerView — co to jest, ViewHolder i Adapter w Android

Autor: IT Sectr Opublikowano: 2026-02-23 Czas czytania: 8 min

RecyclerView — komponent Android Jetpack do wydajnego wyświetlania dużych zbiorów danych w postaci list i siatek. W przeciwieństwie do ListView, RecyclerView ponownie wykorzystuje ViewHoldery i zarządza układem przez LayoutManager. Według Google (Android Developers, 2026), RecyclerView obsługuje do 60 klatek na sekundę podczas przewijania listy z 1000+ elementów dzięki puli ViewHolderów i algorytmowi różnicowemu DiffUtil. Więcej o architekturze aplikacji Android przeczytasz w naszym artykule o ListView.

Najważniejsze

  • RecyclerView — nowoczesny komponent do list w Android, który zastąpił ListView w Android 5.0 (API 21).
  • ViewHolder — wzorzec do buforowania referencji do View, przyspieszający ponowne wykorzystanie komórek podczas przewijania.
  • Adapter — łącznik między danymi a RecyclerView, odpowiedzialny za tworzenie ViewHolderów i wiązanie danych.
  • LayoutManager — określa rozmieszczenie elementów: lista pionowa/pozioma (LinearLayoutManager), siatka (GridLayoutManager), kaskada (StaggeredGridLayoutManager).
  • DiffUtil — narzędzie do obliczania różnic między starą a nową listą, minimalizujące przerysowywanie elementów.

Czym jest RecyclerView?

RecyclerView — to komponent biblioteki Android Jetpack, przedstawiony na Google I/O 2014 jako część Android Support Library v7. Jest przeznaczony do wyświetlania dynamicznych list i siatek z wysoką wydajnością. RecyclerView pojawił się jako zamiennik ListView i rozwiązuje kluczowy problem poprzednika — brak wymuszonego ponownego wykorzystania ViewHolderów.

Architektura RecyclerView opiera się na wzorcu Model-View-Adapter: dane są przechowywane w modelu (List, LiveData, Flow), wyświetlaniem zarządza Adapter, a układ kontroluje LayoutManager. Każdy komponent odpowiada za swoją strefę odpowiedzialności, co czyni system elastycznym i rozszerzalnym.

Według ankiety Android Developers (2025), RecyclerView jest używany w 78% aplikacji Android z top-100 Google Play. Wydajność przewijania listy z 1000+ elementów pozostaje stabilna na 60 FPS na urządzeniach średniej klasy dzięki trzem mechanizmom: pula ViewHolderów, różnicowe obliczanie aktualizacji i asynchroniczne ładowanie danych.

Kiedy używać RecyclerView

RecyclerView jest optymalny do: list z nieznaną liczbą elementów (kanały, czaty, logi), siatek z N kolumn (galerie, katalogi), układów kaskadowych (tablice Pinterest), list z animacją dodawania/usuwania elementów. Dla prostych ekranów z 2–5 elementami LinearLayout lub ScrollView są prostsze i wydajniejsze — RecyclerView dodaje narzut.

Konfiguracja zależności

Aby użyć RecyclerView, dodaj zależność w build.gradle (app): implementation 'androidx.recyclerview:recyclerview:1.4.0'. Minimalna wersja API — 14 (Android 4.0). Od AndroidX RecyclerView 1.3.0 dostępne są moduły recyclerview-selection do zaznaczania elementów i recyclerview-swipe do przesuwania.

Jak działa RecyclerView: trzy kluczowe komponenty

RecyclerView jest podzielony na trzy niezależne warstwy: Adapter zarządza danymi i ViewHolderami, LayoutManager odpowiada za pozycjonowanie elementów, ItemAnimator kontroluje animacje. Taka architektura pozwala zastąpić dowolną warstwę bez zmiany pozostałych — na przykład przejść z LinearLayoutManager na GridLayoutManager bez zmiany kodu Adaptera.

KomponentObowiązkiImplementacja
AdapterTworzenie ViewHolderów, wiązanie danych z View, powiadamianie o zmianachRecyclerView.Adapter<VH>
ViewHolderBuforowanie referencji do View, unikanie findViewById()RecyclerView.ViewHolder
LayoutManagerRozmieszczanie elementów, określanie kierunku przewijaniaLinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager
ItemAnimatorAnimacja dodawania, usuwania, przenoszenia elementówDefaultItemAnimator
ItemDecorationRysowanie separatorów, odstępów, tła między elementamiRecyclerView.ItemDecoration

Cykl pracy: (1) Adapter tworzy ViewHolder przez onCreateViewHolder(), (2) LayoutManager określa pozycję nowego View na ekranie, (3) Adapter wiąże dane przez onBindViewHolder(), (4) podczas przewijania ViewHoldery, które zniknęły z ekranu, trafiają do puli (RecycledViewPool) do ponownego wykorzystania. Zamiast tworzyć nowe View, ponownie wykorzystuje się istniejące — to kluczowy mechanizm wydajności.

Implementacja ViewHolder w RecyclerView

ViewHolder — to klasa przechowująca referencje do View (TextView, ImageView itp.) wewnątrz elementu listy. Bez ViewHolder przy każdym przewijaniu system wywoływałby findViewById() — jedną z najdroższych operacji Android UI. ViewHolder eliminuje to wywołanie, zapamiętując referencje po pierwszym powiązaniu.

kotlin
// Model danych
data class Article(
    title: String,
    summary: String,
    author: String,
    imageUrl: String?
)

// ViewHolder — przechowuje referencje do 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
    }
}

Praktyczna zasada: każdy View w układzie elementu powinien być zadeklarowany jako właściwość ViewHolder z findViewById() dokładnie raz — w konstruktorze. Metoda bind() nie wywołuje findViewById(), a jedynie ustawia tekst, kolory i słuchacze. Takie podejście przyspiesza przewijanie listy o 30–50% według Google (Android Performance Patterns, 2025).

Typy LayoutManager: wybór rozmieszczenia elementów

LayoutManager określa, jak elementy są rozmieszczone wewnątrz RecyclerView. Domyślnie Android udostępnia trzy implementacje: LinearLayoutManager, GridLayoutManager i StaggeredGridLayoutManager. Wybór LayoutManager wpływa na odbiór danych przez użytkownika i wydajność przewijania.

LayoutManagerRozmieszczenieKiedy używaćMetoda ustawienia
LinearLayoutManagerLista (pionowa lub pozioma)Kanały, czaty, powiadomienia, listy produktówLinearLayoutManager(context)
GridLayoutManagerSiatka z N kolumnGalerie, katalogi, ikony, siatka obrazówGridLayoutManager(context, spanCount)
StaggeredGridLayoutManagerSiatka kaskadowa (różna wysokość elementów)Tablice Pinterest, notatki, galerie masonryStaggeredGridLayoutManager(spanCount, orientation)
kotlin
// Ustawianie LinearLayoutManager w 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)

        // Optymalizacja: stały rozmiar + pula
        recyclerView.setHasFixedSize(true)
        recyclerView.setItemViewCacheSize(20)

        // Separator między elementami
        val divider = DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)
        recyclerView.addItemDecoration(divider)
    }
}

Wydajność: LinearLayoutManager z przewijaniem pionowym — najszybsza opcja, ponieważ elementy są rozmieszczane sekwencyjnie, a LayoutManager oblicza pozycje w O(1). GridLayoutManager wymaga dodatkowych obliczeń do podziału na kolumny, ale pozostaje wydajny przy stałym spanCount. StaggeredGridLayoutManager jest najwolniejszy z trzech, ponieważ musi obliczać pozycję elementu w kaskadzie uwzględniając wysokość sąsiednich elementów. Używaj go tylko gdy wizualnie wymagana jest różna wysokość komórek.

Adapter i DiffUtil: wydajna aktualizacja danych

Adapter w RecyclerView implementuje wzorzec Adapter z GoF: przekształca dane (List<T>) w ViewHoldery wyświetlane na ekranie. Przy zmianie danych Adapter może powiadomić RecyclerView przez metody notifyDataSetChanged(), notifyItemInserted() i podobne. Problem polega na tym, że notifyDataSetChanged() przerysowuje wszystkie widoczne elementy, co prowadzi do drgań (jank).

kotlin
// Adapter z DiffUtil do wydajnej aktualizacji
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

    // Aktualizacja listy przez DiffUtil
    fun updateArticles(newArticles: List<Article>) {
        val diffCallback = ArticleDiffCallback(articles, newArticles)
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        articles = newArticles
        diffResult.dispatchUpdatesTo(this)
    }
}

// Callback dla 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 używa algorytmu Eugene W. Myers' difference algorithm, który oblicza minimalną liczbę operacji (insert, remove, move, change) potrzebnych do przekształcenia starej listy w nową. Dla listy 100 elementów DiffUtil działa w 1–5 ms (Google, 2025). Dla dużych list (10000+) używaj AsyncListDiffer lub PagingDataAdapter z biblioteki Paging — wykonują obliczenia w tle.

RecyclerView vs ListView: porównanie

ListView — poprzednik RecyclerView, pojawił się w Android 1.0 (API 1). Również wyświetla listy, ale nie narzuca ViewHolder, nie obsługuje LayoutManager i nie umie animować zmian. RecyclerView został zaprojektowany jako zamiennik ListView z bardziej rygorystyczną architekturą i wydajnością.

KryteriumRecyclerViewListView
ViewHolderObowiązkowy (architektura)Zalecany, ale nie obowiązkowy
LayoutManagerPodział: lista, siatka, kaskadaTylko lista pionowa
Animacja zmianDefaultItemAnimator od razuBrak wbudowanego wsparcia
Powiadomienia o zmianachPunktowe: notifyItemInserted/RemovednotifyDataSetChanged() tylko cała lista
DiffUtilWsparcie przez DiffUtil.CallbackBrak odpowiednika
SeparatoryItemDecoration (niestandardowe)android:divider (wbudowany)
Minimalna wersjaAPI 14 (Android 4.0) przez AndroidXAPI 1 (wszystkie wersje)

Zalecenie Google (Android Developers, 2026): używaj RecyclerView dla wszystkich nowych projektów. ListView można pozostawić w starych bazach kodu (legacy), gdzie migracja nie uzasadnia kosztów. RecyclerView zapewnia lepszą wydajność na 100+ elementach, obsługuje przewijanie poziome i siatki bez dodatkowych obejść. W Android 15 ListView jest oficjalnie oznaczony jako częściowo przestarzały.

Często zadawane pytania

RecyclerView nie wyświetla elementów — co robić?

Sprawdź trzy warunki: (1) Adapter ustawiony przez recyclerView.adapter = adapter, (2) LayoutManager ustawiony przez recyclerView.layoutManager = LinearLayoutManager(context), (3) dane na liście nie są puste i adapter został powiadomiony (notifyDataSetChanged()). Typowy błąd — ustawienie danych po wywołaniu notifyDataSetChanged(). Dane powinny być przypisane przed powiadomieniem. Sprawdź rozmiar listy: adapter.itemCount powinien być większy niż 0.

Dlaczego RecyclerView przewija się z opóźnieniami?

Opóźnienia podczas przewijania (jank) występują, gdy onBindViewHolder() wykonuje ciężkie operacje: ładowanie obrazów bez buforowania, findViewById() wewnątrz bind, złożone obliczenia. Rozwiązania: (1) używaj biblioteki Glide lub Coil do asynchronicznego ładowania obrazów, (2) przenieś wszystkie findViewById() do konstruktora ViewHolder, (3) do obliczeń różnicowych używaj AsyncListDiffer. Włącz profilowanie GPU w Android Studio (Profile GPU Rendering), aby znaleźć wolne klatki.

Jak zrobić poziomy RecyclerView?

Przekaż orientację do LayoutManager: LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false). Drugi parametr to reverseLayout (false = od lewej do prawej). Dla poziomej siatki używaj GridLayoutManager z orientacją poziomą lub niestandardowy LinearSnapHelper do przewijania stronicowego. Listy poziome dobrze nadają się do karuzel produktów, obrazów, kategorii.

Jak dodać click listener do elementu RecyclerView?

RecyclerView nie ma wbudowanego onClickListener (w przeciwieństwie do ListView z onItemClickListener). Zaimplementuj go w ViewHolder: przekaż lambdę do konstruktora i ustaw itemView.setOnClickListener. Przykład: class ArticleViewHolder(itemView: View, val onItemClick: (Article) -> Unit) : RecyclerView.ViewHolder(itemView). Wywołuj onItemClick(article) wewnątrz bind(). Alternatywa — ustaw RecyclerView.addOnItemTouchListener() do obsługi gestów.

Czym jest RecycledViewPool i jak go skonfigurować?

RecycledViewPool — wewnętrzna pula ViewHolderów, które stały się niewidoczne podczas przewijania. Zamiast niszczenia są przechowywane w puli i ponownie wykorzystywane. Domyślnie pula przechowuje 5 ViewHolderów każdego typu. Zwiększ rozmiar dla złożonych układów: recyclerView.getRecycledViewPool().setMaxRecycledViews(VIEW_TYPE_NORMAL, maxCount). Jeśli w RecyclerView jest kilka typów View (viewType), pula przechowuje osobne stosy dla każdego. Współdzielenie RecycledViewPool między różnymi RecyclerView oszczędza pamięć w ekranach z zagnieżdżonymi listami.

Podsumowanie

  • RecyclerView — nowoczesny komponent Android Jetpack do list i siatek z wydajnością do 60 FPS.
  • ViewHolder — obowiązkowy wzorzec do buforowania View, eliminujący findViewById() przy każdym przewijaniu.
  • Adapter — zarządza danymi i tworzeniem ViewHolderów przez onCreateViewHolder i onBindViewHolder.
  • LayoutManager — trzy implementacje: LinearLayoutManager (lista), GridLayoutManager (siatka), StaggeredGridLayoutManager (kaskada).
  • DiffUtil — algorytm do minimalnej aktualizacji listy: punktowe przerysowanie zamiast pełnego.
  • RecyclerView jest używany w 78% aplikacji Android z top-100 i oficjalnie zalecany przez Google zamiast ListView.
  • Wydajność RecyclerView osiągana jest dzięki puli ViewHolderów, punktowym powiadomieniom i asynchronicznym obliczeniom różnicowym.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również