RecyclerView — що це, ViewHolder та Adapter в Android

Автор: IT Sectr Опубліковано: 2026-02-23 Час читання: 8 хв

RecyclerView — компонент Android Jetpack для ефективного відображення великих наборів даних у вигляді списків і сіток. На відміну від ListView, RecyclerView перевикористовує ViewHolder'и та керує розміткою через LayoutManager. За даними Google (Android Developers, 2026), RecyclerView обробляє до 60 кадрів на секунду під час прокручування списку з 1000+ елементів завдяки пулінгу 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 на пристроях середнього сегмента завдяки трьом механізмам: пулінг ViewHolder'ів, диф-розрахунок оновлень та асинхронне завантаження даних.

Коли використовувати RecyclerView

RecyclerView оптимальний для: списків із невідомою кількістю елементів (стрічки, чати, логи), сіток із N колонок (галереї, каталоги), каскадних макетів (дошки Pinterest), списків з анімацією додавання/видалення елементів. Для простих екранів із 2–5 елементами LinearLayout або ScrollView простіші та ефективніші — RecyclerView додає накладні витрати.

Налаштування залежності

Для використання 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'и, що пішли за екран, потрапляють у пул (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 у макеті item-розмітки має бути оголошений як властивість ViewHolder з findViewById() рівно один раз — у конструкторі. Метод bind() не викликає findViewById(), а тільки встановлює текст, кольори та слухачі. Такий підхід прискорює прокручування списку на 30–50% за даними Google (Android Performance Patterns, 2025).

Типи LayoutManager: вибір розташування елементів

LayoutManager визначає, як елементи розташовуються всередині RecyclerView. За замовчуванням Android надає три реалізації: LinearLayoutManager, GridLayoutManager і StaggeredGridLayoutManager. Вибір LayoutManager впливає на сприйняття даних користувачем і продуктивність прокручування.

LayoutManagerРозташуванняКоли використовуватиМетод встановлення
LinearLayoutManagerСписок (вертикальний або горизонтальний)Стрічки, чати, сповіщення, списки товарів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)

        // Оптимізація: фіксований розмір + пул
        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 мс (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 — внутрішній пул ViewHolder'ів, які стали невидимими при скролі. Замість знищення вони зберігаються в пулі та перевикористовуються. За замовчуванням пул зберігає 5 ViewHolder'ів кожного типу. Збільште розмір для складних макетів: recyclerView.getRecycledViewPool().setMaxRecycledViews(VIEW_TYPE_NORMAL, maxCount). Якщо в RecyclerView кілька типів View (viewType), пул зберігає окремі стеки для кожного. Спільне використання 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 досягається за рахунок пулінгу ViewHolder'ів, точкових сповіщень та асинхронного диф-розрахунку.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також