Kotlin RecyclerView Basics

RecyclerView is the standard Android widget for displaying long, scrollable lists efficiently. It recycles item views as you scroll — instead of creating a new view for every item, it reuses off-screen views with new data. This keeps large lists smooth and memory-efficient.

Why RecyclerView Instead of ListView


ListView (old):
  Creates a new view for each item as you scroll
  Slow and memory-heavy for large datasets
  No built-in animation or layout flexibility

RecyclerView (modern):
  Recycles views — reuses off-screen views with new data
  Works with any layout (vertical, horizontal, grid)
  Built-in item animations
  Required adapter pattern enforces good architecture

How RecyclerView Works


┌─────────────────────────────────────────────────────┐
│                   RecyclerView                      │
│                                                     │
│  ┌─────────────┐  ← visible items on screen         │
│  │  Item View  │                                    │
│  ├─────────────┤                                    │
│  │  Item View  │                                    │
│  ├─────────────┤                                    │
│  │  Item View  │                                    │
│  └─────────────┘                                    │
│                                                     │
│  LayoutManager → arranges items (Linear/Grid)       │
│  Adapter       → provides data for each position    │
│  ViewHolder    → holds references to item views     │
└─────────────────────────────────────────────────────┘

When an item scrolls off screen:
  ViewHolder is put in a "recycle pool"
  New data is bound to the recycled ViewHolder
  → No new views created → smooth and fast

Step 1: Add Dependency

// In app/build.gradle.kts:
dependencies {
    implementation("androidx.recyclerview:recyclerview:1.3.2")
}

Step 2: Create Item Layout (res/layout/item_product.xml)

<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="12dp">

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

    <TextView
        android:id="@+id/productPrice"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:textStyle="bold" />

</LinearLayout>

Step 3: Create the Adapter

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

data class Product(val name: String, val price: Double)

class ProductAdapter(
    private val products: List,
    private val onItemClick: (Product) -> Unit
) : RecyclerView.Adapter() {

    // ViewHolder: stores references to the views inside one item row
    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val nameText:  TextView = itemView.findViewById(R.id.productName)
        val priceText: TextView = itemView.findViewById(R.id.productPrice)
    }

    // Called when RecyclerView needs a new ViewHolder (new cell)
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_product, parent, false)
        return ViewHolder(view)
    }

    // Called to bind data to a recycled or new ViewHolder
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val product = products[position]
        holder.nameText.text  = product.name
        holder.priceText.text = "₹${product.price}"
        holder.itemView.setOnClickListener { onItemClick(product) }
    }

    // Total number of items in the list
    override fun getItemCount() = products.size
}

Step 4: Set Up RecyclerView in Activity

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class ProductListActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_product_list)

        val products = listOf(
            Product("Laptop",   75000.0),
            Product("Mouse",      800.0),
            Product("Keyboard",  1500.0),
            Product("Monitor",  18000.0),
            Product("Webcam",    3000.0)
        )

        val recyclerView: RecyclerView = findViewById(R.id.recyclerView)

        // LinearLayoutManager = vertical scrolling list
        recyclerView.layoutManager = LinearLayoutManager(this)

        // Set the adapter with a click handler
        recyclerView.adapter = ProductAdapter(products) { product ->
            Toast.makeText(this, "Selected: ${product.name}", Toast.LENGTH_SHORT).show()
        }
    }
}

Activity Layout (activity_product_list.xml)

<RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Layout Manager Options

// Vertical list (default)
LinearLayoutManager(this)

// Horizontal scrolling list
LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)

// 2-column grid
GridLayoutManager(this, 2)

// Staggered grid (Pinterest-style)
StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)

Updating the List Efficiently

// After data changes, tell the adapter what changed:
adapter.notifyItemInserted(products.size - 1)    // one item added at end
adapter.notifyItemRemoved(position)               // one item removed
adapter.notifyItemChanged(position)               // one item updated
adapter.notifyDataSetChanged()                    // entire list changed (avoid if possible)

// Best practice: use DiffUtil or ListAdapter for automatic diffing

Leave a Comment

Your email address will not be published. Required fields are marked *