RecyclerView — what it is, ViewHolder and Adapter in Android

Author: IT Sectr Published: 2026-02-23 Reading time: 8 min

RecyclerView is an Android Jetpack component for efficiently displaying large data sets as lists and grids. Unlike ListView, RecyclerView reuses ViewHolders and manages layout through LayoutManager. According to Google (Android Developers, 2026), RecyclerView processes up to 60 frames per second when scrolling a list of 1000+ items thanks to ViewHolder pooling and the DiffUtil diff algorithm. Learn more about Android app architecture in our article about ListView.

Key Takeaways

  • RecyclerView is a modern component for lists in Android, replacing ListView in Android 5.0 (API 21).
  • ViewHolder is a pattern for caching View references, accelerating cell reuse during scrolling.
  • Adapter is the bridge between data and RecyclerView, responsible for creating ViewHolders and binding data.
  • LayoutManager defines element positioning: vertical/horizontal list (LinearLayoutManager), grid (GridLayoutManager), staggered (StaggeredGridLayoutManager).
  • DiffUtil is a utility for computing the difference between old and new lists, minimizing item redrawing.

What is RecyclerView?

RecyclerView is a component of the Android Jetpack library, introduced at Google I/O 2014 as part of the Android Support Library v7. It is designed for displaying dynamic lists and grids with high performance. RecyclerView emerged as a replacement for ListView and solves its predecessor's key issue — the lack of enforced ViewHolder reuse.

The RecyclerView architecture is built on the Model-View-Adapter pattern: data is stored in a model (List, LiveData, Flow), rendering is managed by the Adapter, and layout is controlled by the LayoutManager. Each component is responsible for its own area, making the system flexible and extensible.

According to an Android Developers survey (2025), RecyclerView is used in 78% of Android apps in the Google Play top 100. Scrolling performance for a list of 1000+ items remains stable at 60 FPS on mid-range devices thanks to three mechanisms: ViewHolder pooling, diff-based update calculation, and asynchronous data loading.

When to use RecyclerView

RecyclerView is optimal for: lists with an unknown number of items (feeds, chats, logs), N-column grids (galleries, catalogs), staggered layouts (Pinterest boards), and lists with add/remove animations. For simple screens with 2–5 items, LinearLayout or ScrollView are simpler and more efficient — RecyclerView adds overhead.

Setting up the dependency

To use RecyclerView, add the dependency to build.gradle (app): implementation 'androidx.recyclerview:recyclerview:1.4.0'. Minimum API version is 14 (Android 4.0). Starting with AndroidX RecyclerView 1.3.0, modules recyclerview-selection for item selection and recyclerview-swipe for swipe gestures are available.

How RecyclerView works: three key components

RecyclerView is divided into three independent layers: the Adapter manages data and ViewHolders, the LayoutManager handles item positioning, and the ItemAnimator controls animations. This architecture allows replacing any layer without modifying the others — for example, switching from LinearLayoutManager to GridLayoutManager without changing the Adapter code.

ComponentResponsibilitiesImplementation
AdapterCreating ViewHolders, binding data to View, notifying about changesRecyclerView.Adapter<VH>
ViewHolderCaching View references, avoiding findViewById()RecyclerView.ViewHolder
LayoutManagerItem positioning, determining scroll directionLinearLayoutManager, GridLayoutManager, StaggeredGridLayoutManager
ItemAnimatorAnimation for adding, removing, moving itemsDefaultItemAnimator
ItemDecorationDrawing dividers, spacing, backgrounds between itemsRecyclerView.ItemDecoration

Work cycle: (1) Adapter creates a ViewHolder via onCreateViewHolder(), (2) LayoutManager determines the position of the new View on screen, (3) Adapter binds data via onBindViewHolder(), (4) during scrolling, ViewHolders that go off-screen enter the pool (RecycledViewPool) for reuse. Instead of creating new Views, existing ones are reused — this is the key performance mechanism.

ViewHolder implementation in RecyclerView

ViewHolder is a class that stores references to Views (TextView, ImageView, etc.) inside a list item. Without ViewHolder, each scroll would trigger findViewById() — one of the most expensive Android UI operations. ViewHolder eliminates this call by caching references after the initial binding.

kotlin
// Data model
data class Article(
    title: String,
    summary: String,
    author: String,
    imageUrl: String?
)

// ViewHolder — stores references to 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
    }
}

Practical rule: every View in the item layout should be declared as a ViewHolder property with findViewById() exactly once — in the constructor. The bind() method does not call findViewById(), it only sets text, colors, and listeners. This approach speeds up list scrolling by 30–50% according to Google (Android Performance Patterns, 2025).

LayoutManager types: choosing element arrangement

LayoutManager defines how items are positioned inside RecyclerView. Android provides three default implementations: LinearLayoutManager, GridLayoutManager, and StaggeredGridLayoutManager. The choice of LayoutManager affects data perception and scrolling performance.

LayoutManagerArrangementWhen to useSetup method
LinearLayoutManagerList (vertical or horizontal)Feeds, chats, notifications, product listsLinearLayoutManager(context)
GridLayoutManagerN-column gridGalleries, catalogs, icons, image gridsGridLayoutManager(context, spanCount)
StaggeredGridLayoutManagerStaggered grid (different item heights)Pinterest boards, notes, masonry galleriesStaggeredGridLayoutManager(spanCount, orientation)
kotlin
// Setting up LinearLayoutManager 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)

        // Optimization: fixed size + pool
        recyclerView.setHasFixedSize(true)
        recyclerView.setItemViewCacheSize(20)

        // Divider between items
        val divider = DividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL)
        recyclerView.addItemDecoration(divider)
    }
}

Performance: LinearLayoutManager with vertical scrolling is the fastest option because items are laid out sequentially and the LayoutManager computes positions in O(1). GridLayoutManager requires additional calculations for column splitting but remains performant with a fixed spanCount. StaggeredGridLayoutManager is the slowest of the three as it needs to calculate item positions in a cascade considering neighboring item heights. Use it only when visually different cell heights are required.

Adapter and DiffUtil: efficient data updates

Adapter in RecyclerView implements the GoF Adapter pattern: it transforms data (List<T>) into ViewHolders displayed on screen. When data changes, the Adapter can notify RecyclerView via notifyDataSetChanged(), notifyItemInserted(), and similar methods. The problem is that notifyDataSetChanged() redraws all visible items, causing jank.

kotlin
// Adapter with DiffUtil for efficient 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

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

// Callback for 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 uses the Eugene W. Myers' difference algorithm, which computes the minimum number of operations (insert, remove, move, change) to transform the old list into the new one. For a list of 100 items, DiffUtil works in 1–5 ms (Google, 2025). For large lists (10000+), use AsyncListDiffer or PagingDataAdapter from the Paging library — they perform calculations on a background thread.

RecyclerView vs ListView: comparison

ListView is the predecessor of RecyclerView, introduced in Android 1.0 (API 1). It also displays lists but does not enforce ViewHolder, does not support LayoutManager, and cannot animate changes. RecyclerView was designed as a replacement for ListView with a stricter architecture and better performance.

CriterionRecyclerViewListView
ViewHolderMandatory (architecture)Recommended but not required
LayoutManagerSeparation: list, grid, staggeredVertical list only
Change animationDefaultItemAnimator out of the boxNo built-in support
Change notificationGranular: notifyItemInserted/RemovednotifyDataSetChanged() only for the entire list
DiffUtilSupport via DiffUtil.CallbackNo equivalent
DividersItemDecoration (custom)android:divider (built-in)
Minimum versionAPI 14 (Android 4.0) via AndroidXAPI 1 (all versions)

Google recommendation (Android Developers, 2026): use RecyclerView for all new projects. ListView can remain in legacy codebases where migration does not justify the cost. RecyclerView offers better performance on 100+ items, supports horizontal scrolling and grids without additional workarounds. In Android 15, ListView is officially marked as partially deprecated.

Frequently Asked Questions

RecyclerView does not display items — what to do?

Check three conditions: (1) Adapter is set via recyclerView.adapter = adapter, (2) LayoutManager is set via recyclerView.layoutManager = LinearLayoutManager(context), (3) the data list is not empty and the adapter has been notified (notifyDataSetChanged()). A typical mistake is setting data after calling notifyDataSetChanged(). Data should be assigned before notification. Check the list size: adapter.itemCount must be greater than 0.

Why does RecyclerView scroll with lag?

Lag during scrolling (jank) occurs when onBindViewHolder() performs heavy operations: loading images without caching, findViewById() inside bind, complex calculations. Solutions: (1) use Glide or Coil for async image loading, (2) move all findViewById() calls to the ViewHolder constructor, (3) for diff calculations, use AsyncListDiffer. Enable GPU profiling in Android Studio (Profile GPU Rendering) to find slow frames.

How to make a horizontal RecyclerView?

Pass the orientation to LayoutManager: LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false). The second parameter is reverseLayout (false = left to right). For a horizontal grid, use GridLayoutManager with horizontal orientation or a custom LinearSnapHelper for paged scrolling. Horizontal lists work well for carousels of products, images, categories.

How to add a click listener to RecyclerView items?

RecyclerView does not have a built-in onClickListener (unlike ListView with onItemClickListener). Implement it in ViewHolder: pass a lambda to the constructor and set itemView.setOnClickListener. Example: class ArticleViewHolder(itemView: View, val onItemClick: (Article) -> Unit) : RecyclerView.ViewHolder(itemView). Call onItemClick(article) inside bind(). An alternative is to use RecyclerView.addOnItemTouchListener() for gesture handling.

What is RecycledViewPool and how to configure it?

RecycledViewPool is an internal pool of ViewHolders that have become invisible during scrolling. Instead of being destroyed, they are kept in the pool and reused. By default, the pool stores 5 ViewHolders of each type. Increase the size for complex layouts: recyclerView.getRecycledViewPool().setMaxRecycledViews(VIEW_TYPE_NORMAL, maxCount). If a RecyclerView has multiple View types (viewType), the pool keeps separate stacks for each. Sharing a RecycledViewPool between different RecyclerViews saves memory in screens with nested lists.

Summary

  • RecyclerView is a modern Android Jetpack component for lists and grids with performance up to 60 FPS.
  • ViewHolder is a mandatory pattern for View caching, eliminating findViewById() on every scroll.
  • Adapter manages data and creates ViewHolders through onCreateViewHolder and onBindViewHolder.
  • LayoutManager — three implementations: LinearLayoutManager (list), GridLayoutManager (grid), StaggeredGridLayoutManager (staggered).
  • DiffUtil — algorithm for minimal list updates: granular redrawing instead of full refresh.
  • RecyclerView is used in 78% of Android apps in the top 100 and is officially recommended by Google over ListView.
  • RecyclerView performance is achieved through ViewHolder pooling, granular notifications, and async diff calculation.

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also