RecyclerView — шта је то, ViewHolder и Adapter у Android-у

Аутор: IT Sectr Објављено: 2026-02-23 Време читања: 8 мин

RecyclerView — компонента Android Jetpack за ефикасно приказивање великих скупова података у виду листи и мрежа. За разлику од ListView, RecyclerView поново користи ViewHolder-е и управља распоредом преко LayoutManager-а. Према Google-у (Android Developers, 2026), RecyclerView обрађује до 60 кадрова у секунди при померању листе од 1000+ елемената захваљујући pool-у ViewHolder-а и диф-алгоритму DiffUtil. Више о архитектури Android апликација прочитајте у нашем чланку о ListView.

Главно

  • RecyclerView — савремена компонента за листе у Android-у, која је заменила ListView у Android 5.0 (API 21).
  • ViewHolder — образац за кеширање референци на View, убрзавајући поновно коришћење ћелија при померању.
  • Adapter — веза између података и RecyclerView-а, задужен за стварање ViewHolder-а и повезивање података.
  • LayoutManager — одређује распоред елемената: вертикална/хоризонтална листа (LinearLayoutManager), мрежа (GridLayoutManager), каскада (StaggeredGridLayoutManager).
  • DiffUtil — алат за израчунавање разлике између старе и нове листе, минимизирајући поновно цртање елемената.

Шта је RecyclerView?

RecyclerView — компонента библиотеке Android Jetpack, представљена на Google I/O 2014 као део Android Support Library v7. Намењен је за приказивање динамичких листи и мрежа са високим перформансама. RecyclerView се појавио као замена за ListView и решава кључни проблем претходника — недостатак принудног поновног коришћења ViewHolder-а.

Архитектура RecyclerView-а је изграђена на обрасцу Model-View-Adapter: подаци се чувају у моделу (List, LiveData, Flow), приказом управља Adapter, а распоред контролише LayoutManager. Свака компонента је одговорна за своју зону одговорности, што чини систем флексибилним и проширивим.

Према анкети Android Developers (2025), RecyclerView се користи у 78% Android апликација из топ-100 Google Play-а. Перформансе померања листе од 1000+ елемената остају стабилне на 60 FPS на уређајима средњег сегмента захваљујући три механизма: pool ViewHolder-а, диф-прорачун ажурирања и асинхроно учитавање података.

Када користити RecyclerView

RecyclerView је оптималан за: листе са непознатим бројем елемената (feed-ови, четови, логови), мреже са N колона (галерије, каталози), каскадне распореде (Pinterest табле), листе са анимацијом додавања/уклањања елемената. За једноставне екране са 2-5 елемената LinearLayout или ScrollView су једноставнији и ефикаснији — RecyclerView додаје додатни overhead.

Подешавање зависности

За коришћење RecyclerView-а додајте зависност у build.gradle (app): implementation 'androidx.recyclerview:recyclerview:1.4.0'. Минимална верзија API-ја — 14 (Android 4.0). Почевши од AndroidX RecyclerView 1.3.0, доступни су модули recyclerview-selection за избор елемената и recyclerview-swipe за превлачење.

Како ради RecyclerView: три кључне компоненте

RecyclerView је подељен на три независна слоја: Adapter управља подацима и ViewHolder-има, LayoutManager је задужен за позиционирање елемената, ItemAnimator контролише анимације. Оваква архитектура омогућава замену било ког слоја без мењања осталих — на пример, прелазак са LinearLayoutManager-а на GridLayoutManager без мењања кода Adapter-а.

КомпонентаОдговорностиИмплементација
AdapterКреирање ViewHolder-а, повезивање података са View, обавештавање о променамаRecyclerView.Adapter<VH>
ViewHolderКеширање референци на View, избегавање findViewById()RecyclerView.ViewHolder
LayoutManagerРаспоређивање елемената, одређивање смера померањаLinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager
ItemAnimatorАнимација додавања, уклањања, премештања елеменатаDefaultItemAnimator
ItemDecorationЦртање разделника, размака, позадина између елеменатаRecyclerView.ItemDecoration

Циклус рада: (1) Adapter креира ViewHolder кроз onCreateViewHolder(), (2) LayoutManager одређује позицију новог View-а на екрану, (3) Adapter повезује податке кроз onBindViewHolder(), (4) при померању, ViewHolder-и који су изашли са екрана одлазе у pool (RecycledViewPool) за поновно коришћење. Уместо стварања нових View-ова, поново се користе постојећи — ово је кључни механизам перформанси.

Имплементација ViewHolder-а у RecyclerView-у

ViewHolder — класа која чува референце на View (TextView, ImageView итд.) унутар елемента листе. Без ViewHolder-а при сваком померању систем би позивао findViewById() — једну од најскупљих операција Android UI-ја. ViewHolder елиминише овај позив, памтећи референце након првог повезивања.

kotlin
// Модел података
data class Article(
    title: String,
    summary: String,
    author: String,
    imageUrl: String?
)

// ViewHolder — чува референце на 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
    }
}

Практично правило: сваки View у распореду елемента треба да буде декларисан као својство ViewHolder-а са findViewById() тачно једном — у конструктору. Метод bind() не позива findViewById(), већ само поставља текст, боје и слушаоце. Овај приступ убрзава померање листе за 30-50% према Google-у (Android Performance Patterns, 2025).

Типови LayoutManager-а: избор распореда елемената

LayoutManager одређује како су елементи распоређени унутар RecyclerView-а. Подразумевано, Android нуди три имплементације: LinearLayoutManager, GridLayoutManager и StaggeredGridLayoutManager. Избор LayoutManager-а утиче на перцепцију података од стране корисника и перформансе померања.

LayoutManagerРаспоредКада користитиМетода подешавања
LinearLayoutManagerЛиста (вертикална или хоризонтална)Feed-ови, четови, обавештења, листе производаLinearLayoutManager(context)
GridLayoutManagerМрежа са N колонаГалерије, каталози, иконе, мрежа сликаGridLayoutManager(context, spanCount)
StaggeredGridLayoutManagerКаскадна мрежа (различите висине елемената)Pinterest табле, белешке, masonry галеријеStaggeredGridLayoutManager(spanCount, orientation)
kotlin
// Подешавање LinearLayoutManager-а у 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)

        // Оптимизација: фиксна величина + pool
        recyclerView.setHasFixedSize(true)
        recyclerView.setItemViewCacheSize(20)

        // Разделник између елемената
        val divider = DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)
        recyclerView.addItemDecoration(divider)
    }
}

Перформансе: LinearLayoutManager са вертикалним померањем је најбржа опција, јер су елементи распоређени секвенцијално и LayoutManager израчунава позиције у O(1). GridLayoutManager захтева додатна израчунавања за поделу на колоне, али остаје ефикасан са фиксним spanCount. StaggeredGridLayoutManager је најспорији од три, јер мора да израчуна позицију елемента у каскади узимајући у обзир висину суседних елемената. Користите га само када је визуелно потребна различита висина ћелија.

Adapter и DiffUtil: ефикасно ажурирање података

Adapter у RecyclerView-у имплементира Adapter образац из GoF-а: претвара податке (List<T>) у ViewHolder-е приказане на екрану. При промени података, Adapter може да обавести RecyclerView кроз методе notifyDataSetChanged(), notifyItemInserted() и сличне. Проблем је у томе што notifyDataSetChanged() поново црта све видљиве елементе, што доводи до трзаја (jank).

kotlin
// Adapter са DiffUtil-ом за ефикасно ажурирање
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

    // Ажурирање листе кроз DiffUtil
    fun updateArticles(newArticles: List<Article>) {
        val diffCallback = ArticleDiffCallback(articles, newArticles)
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        articles = newArticles
        diffResult.dispatchUpdatesTo(this)
    }
}

// Callback за 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 користи алгоритам Eugene W. Myers' difference algorithm који израчунава минимални број операција (insert, remove, move, change) за трансформацију старе листе у нову. За листу од 100 елемената DiffUtil ради за 1-5 ms (Google, 2025). За велике листе (10000+) користите AsyncListDiffer или PagingDataAdapter из Paging библиотеке — они обављају прорачуне у позадинској нити.

RecyclerView vs ListView: поређење

ListView — претходник RecyclerView-а, појавио се у Android 1.0 (API 1). Такође приказује листе, али не намеће ViewHolder, не подржава LayoutManager и не може да анимира промене. RecyclerView је дизајниран као замена за ListView са строжијом архитектуром и бољим перформансама.

КритеријумRecyclerViewListView
ViewHolderОбавезан (архитектура)Препоручује се, али није обавезан
LayoutManagerПодела: листа, мрежа, каскадаСамо вертикална листа
Анимација променаDefaultItemAnimator из кутијеНема уграђену подршку
Обавештавање о променамаТачкасто: notifyItemInserted/RemovednotifyDataSetChanged() само цела листа
DiffUtilПодршка кроз DiffUtil.CallbackНема еквивалент
РазделнициItemDecoration (прилагођени)android:divider (уграђени)
Минимална верзијаAPI 14 (Android 4.0) кроз AndroidXAPI 1 (све верзије)

Google препорука (Android Developers, 2026): користите RecyclerView за све нове пројекте. ListView се може оставити у старим кодним базама (legacy) где миграција не оправдава трошкове. RecyclerView пружа боље перформансе на 100+ елемената, подржава хоризонтално померање и мреже без додатних решења. У Android 15, ListView је званично означен као делимично застарео.

Често постављана питања

RecyclerView не приказује елементе — шта радити?

Проверите три услова: (1) Adapter постављен кроз recyclerView.adapter = adapter, (2) LayoutManager постављен кроз recyclerView.layoutManager = LinearLayoutManager(context), (3) подаци у листи нису празни и adapter је обавештен (notifyDataSetChanged()). Типична грешка — постављање података након позива notifyDataSetChanged(). Подаци треба да буду додељени пре обавештења. Проверите величину листе: adapter.itemCount треба да буде већи од 0.

Зашто RecyclerView споро помера?

Успорења при померању (jank) настају када onBindViewHolder() извршава тешке операције: учитавање слика без кеширања, findViewById() унутар bind-а, сложена израчунавања. Решења: (1) користите Glide или Coil библиотеку за асинхроно учитавање слика, (2) преместите све findViewById() у конструктор ViewHolder-а, (3) за диф-прорачуне користите AsyncListDiffer. Укључите GPU профилисање у Android Studio (Profile GPU Rendering) за проналажење спорих кадрова.

Како направити хоризонтални RecyclerView?

Проследите оријентацију LayoutManager-у: LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false). Други параметар је reverseLayout (false = слева надесно). За хоризонталну мрежу користите GridLayoutManager са хоризонталном оријентацијом или прилагођени LinearSnapHelper за странично померање. Хоризонталне листе су погодне за каруселе производа, слика, категорија.

Како додати click listener на елемент RecyclerView-а?

RecyclerView нема уграђени onClickListener (за разлику од ListView-а са onItemClickListener). Имплементирајте га у ViewHolder-у: проследите ламбду у конструктор и поставите itemView.setOnClickListener. Пример: class ArticleViewHolder(itemView: View, val onItemClick: (Article) -> Unit) : RecyclerView.ViewHolder(itemView). Позивајте onItemClick(article) унутар bind(). Алтернатива — поставите RecyclerView.addOnItemTouchListener() за обраду гестова.

Шта је RecycledViewPool и како га подесити?

RecycledViewPool — интерни pool ViewHolder-а који су постали невидљиви при померању. Уместо уништавања, чувају се у pool-у и поново користе. Подразумевано, pool чува 5 ViewHolder-а сваког типа. Повећајте величину за сложене распореде: recyclerView.getRecycledViewPool().setMaxRecycledViews(VIEW_TYPE_NORMAL, maxCount). Ако RecyclerView има више типова View-а (viewType), pool чува одвојене стекове за сваки. Дељење RecycledViewPool-а између различитих RecyclerView-а штеди меморију на екранима са угнежђеним листама.

Закључак

  • RecyclerView — савремена Android Jetpack компонента за листе и мреже са перформансама до 60 FPS.
  • ViewHolder — обавезан образац за кеширање View-а, елиминише findViewById() при сваком померању.
  • Adapter — управља подацима и креирањем ViewHolder-а кроз onCreateViewHolder и onBindViewHolder.
  • LayoutManager — три имплементације: LinearLayoutManager (листа), GridLayoutManager (мрежа), StaggeredGridLayoutManager (каскада).
  • DiffUtil — алгоритам за минимално ажурирање листе: тачкасто поновно цртање уместо потпуног.
  • RecyclerView се користи у 78% Android апликација из топ-100 и званично препоручен од Google-а уместо ListView-а.
  • Перформансе RecyclerView-а се постижу кроз pool ViewHolder-а, тачкаста обавештења и асинхрони диф-прорачун.

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође