Skip to main content
Android Development with Kotlin
CHAPTER 13 Beginner

RecyclerView and ListView

Updated: May 16, 2026
30 min read

# CHAPTER 13

RecyclerView and ListView

1. Introduction

If you build a messaging app, you cannot manually create 50,000 TextView elements in an XML ScrollView. The phone would run out of RAM and instantly crash. How do apps like Twitter and Instagram allow you to scroll through infinite lists flawlessly? They recycle the views. In this chapter, we will master the RecyclerView, the most important UI component in the entire Android ecosystem. We will explore why the legacy ListView was deprecated, understand the powerful Adapter Pattern, construct efficient ViewHolders, and dynamically render massive datasets without dropping a single frame of performance.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Explain why RecyclerView is architecturally superior to ScrollView and ListView.
  • Design a custom XML layout for a single row item.
  • Architect an Adapter class to bridge Kotlin data arrays with XML views.
  • Implement the ViewHolder pattern to cache memory references.
  • Connect the RecyclerView to a LayoutManager in the main Activity.

3. ScrollView vs ListView vs RecyclerView

  • ScrollView: If you have 1,000 items, it creates 1,000 UI elements in memory instantly. Huge memory leak.
  • ListView: An older Android component. It was better, but it was inefficient because it constantly re-searched for XML elements (findViewById) every time the user scrolled, causing lag.
  • RecyclerView: The modern standard. If your screen can only fit 10 items, RecyclerView *only creates 10 XML UI elements*. As you scroll item #1 off the top of the screen, RecyclerView instantly teleports that exact XML box to the bottom of the screen, clears its text, and inserts item #11's data. It literally "recycles" the views!

4. The Architecture (3 Required Pieces)

To make a RecyclerView work, you must architect three separate files:
  1. 1. The Item XML: A layout file dictating exactly what *one single row* looks like.
  1. 2. The Adapter: The Kotlin "Brain" that grabs the list of data and shoves it into the XML rows.
  1. 3. The Activity: Where the RecyclerView physically lives.

5. Step 1: The Item XML (The Row)

Create a new XML file named item_product.xml in res/layout.
xml
12345678910111213141516171819202122232425
<?xml version="1.0" encoding="utf-8"?>
<!-- Notice the height is wrap_content! A row shouldn&#039;t fill the whole screen! -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="16dp"
    android:borderBottomWidth="1dp">

    <TextView
        android:id="@+id/productName"
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/productPrice"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:textColor="#00AA00" />

</LinearLayout>

6. Step 2: The Adapter and ViewHolder

This is the most complex boilerplate code in Android. The ViewHolder caches the findViewById lookups. The Adapter tells the RecyclerView how many items exist, and binds the data to the ViewHolder.
kotlin
12345678910111213141516171819202122232425262728293031323334353637
package com.example.recyclerviewdemo

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

// The Adapter requires a List of Data!
class ProductAdapter(private val productList: List<String>) : 
    RecyclerView.Adapter<ProductAdapter.ProductViewHolder>() {

    // 1. THE VIEWHOLDER: Caches the XML views in memory!
    class ProductViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val nameTextView: TextView = itemView.findViewById(R.id.productName)
        val priceTextView: TextView = itemView.findViewById(R.id.productPrice)
    }

    // 2. onCreateViewHolder: Inflates (creates) the actual XML row
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_product, parent, false)
        return ProductViewHolder(view)
    }

    // 3. onBindViewHolder: The Recycling Phase! Replaces the data in the existing row.
    override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
        val currentProduct = productList[position]
        holder.nameTextView.text = currentProduct
        holder.priceTextView.text = "$99.99" // Hardcoded price for demo
    }

    // 4. getItemCount: Tells the system how big the list is!
    override fun getItemCount(): Int {
        return productList.size
    }
}

7. Step 3: Wiring it in the Activity

In your activity_main.xml, add the RecyclerView:
xml
1234
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

In your MainActivity.kt:

kotlin
123456789101112131415161718
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 1. Generate fake data
        val myData = listOf("Laptop", "Smartphone", "Tablet", "Headphones", "Monitor", "Keyboard", "Mouse")

        // 2. Find the RecyclerView
        val recyclerView: RecyclerView = findViewById(R.id.recyclerView)

        // 3. Set the LayoutManager (Tells it to act like a vertical list, not a grid)
        recyclerView.layoutManager = LinearLayoutManager(this)

        // 4. Attach the Adapter!
        recyclerView.adapter = ProductAdapter(myData)
    }
}

8. Handling Clicks in a RecyclerView

To make a row clickable, you don't add the listener in the Activity. You add it inside the Adapter's onBindViewHolder.
kotlin
123456789
override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
    val currentProduct = productList[position]
    holder.nameTextView.text = currentProduct
    
    // Attaching a click listener to the entire row!
    holder.itemView.setOnClickListener {
        println("User clicked on: $currentProduct")
    }
}

9. Common Mistakes

  • Forgetting the LayoutManager: If you hook up your Adapter perfectly, hit run, and the screen is completely blank, you forgot the LayoutManager! A RecyclerView doesn't know if it is supposed to be a vertical list, a horizontal carousel, or a grid. You MUST assign a LinearLayoutManager or GridLayoutManager.
  • Setting row height to matchparent: If your itemproduct.xml root layout has a height of matchparent, every single row will take up the entire phone screen. You will only see one item at a time! Always set row heights to wrapcontent.

10. Best Practices

  • Never put heavy logic in onBindViewHolder: The onBindViewHolder function fires dozens of times per second as the user scrolls rapidly. If you try to download an image or perform heavy math inside this function, the app will stutter and drop frames. All data should be pre-calculated before it reaches the Adapter.

11. Exercises

  1. 1. Modify the item_product.xml to include an ImageView on the left side of the text.
  1. 2. In MainActivity, change the LinearLayoutManager to a GridLayoutManager(this, 2). Run the app and observe how it instantly becomes a 2-column grid!

12. Coding Challenges

Challenge: The current Adapter only accepts a List<String>. Create a Kotlin Data Class named Product(val name: String, val price: Double). Refactor the ProductAdapter to accept a List<Product>. Update onBindViewHolder to display both the dynamic name and the dynamic price from the Data Class.

13. MCQ Quiz with Answers

Question 1

What is the explicit architectural flaw of the legacy ScrollView that the RecyclerView elegantly solves when rendering lists of 10,000 items?

Question 2

Within the RecyclerView architectural pattern, what is the specific role of the ViewHolder inner class?

14. Interview Questions

  • Q: Explain the mechanical interaction between onCreateViewHolder and onBindViewHolder. In a list of 1000 items on a screen that fits 10 items, roughly how many times will onCreateViewHolder execute versus onBindViewHolder during a full scroll?
  • Q: Describe the functional requirement of the LayoutManager within the RecyclerView architecture.
  • Q: Contrast the implementation of row click events within a RecyclerView Adapter versus setting click listeners directly within an Activity class.

15. FAQs

Q: I have a massive list, and when data updates, I am calling adapter.notifyDataSetChanged(). But I read this is bad practice? A: Yes. notifyDataSetChanged() forces the RecyclerView to completely destroy and redraw every single visible row, even if only one item changed. In professional apps, you use DiffUtil or ListAdapter, which mathematically calculates exactly which row changed and runs a smooth animation specifically for that single row.

16. Summary

In Chapter 13, we mastered the most critical UI component in mobile engineering: the RecyclerView. We abandoned the catastrophic memory-leaks of ScrollView in favor of dynamic view recycling. We architected robust Adapters to serve as the structural bridge between raw data arrays and visual layouts. We implemented the ViewHolder Pattern to cache memory allocations for lightning-fast scrolling, and bound our lists to physical dimensions utilizing the LayoutManager.

17. Next Chapter Recommendation

Our single-screen applications are functioning perfectly. But real apps have dozens of screens. How do we click a product in our RecyclerView and transition to a "Product Details" screen? Proceed to Chapter 14: Navigation Between Activities and Fragments.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·