# How to Implement a RecyclerView in Android Kotlin with Item Click Handling

> Learn how to implement a RecyclerView in Android Kotlin with efficient item click handling. Find a clear example in the JetBrains/kotlin repository.

- Repository: [JetBrains/kotlin](https://github.com/jetbrains/kotlin)
- Tags: tutorial
- Published: 2026-02-20

---

**The JetBrains/kotlin repository provides a minimal, fully-functional example in its Gradle-plugin integration tests that demonstrates how to bind data to a RecyclerView and handle item clicks efficiently using the view tag pattern.**

If you are looking for a straightforward way to implement a RecyclerView in Android Kotlin with basic item click handling, the official Kotlin repository contains a concise reference implementation. This example, located within the `kapt2/android-dbflow` test project, demonstrates the essential pattern for creating an adapter, binding views, and responding to user interactions without unnecessary complexity.

## Project Location in the Kotlin Repository

The complete working example resides in the integration test resources for the Kotlin Gradle plugin. You can find all relevant files in `libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-dbflow/app/src/main/java/mobi/porquenao/poc/kotlin/ui/`. This self-contained module includes the adapter, activity, and layout files necessary for a functional RecyclerView implementation, making it easy to copy into your own projects.

## Layout Structure

### Main Activity Layout

The [`activity_main.xml`](https://github.com/JetBrains/kotlin/blob/main/activity_main.xml) file defines a vertical RecyclerView inside a LinearLayout. The RecyclerView uses `@+id/list` as its identifier and includes vertical scrollbars for user feedback.

```xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ui.MainActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="@style/AppToolbar"/>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingTop="8dp"
        android:paddingBottom="8dp"
        android:scrollbars="vertical"/>
</LinearLayout>

```

### Item Layout

Each list item uses a CardView containing a clickable LinearLayout container. The container uses `android:clickable="true"` and a selectable item background to provide visual feedback, while TextView elements display the title and date.

```xml
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/card"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp">

    <LinearLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:gravity="center_vertical"
        android:padding="16dp"
        android:background="?android:attr/selectableItemBackground"
        android:clickable="true">

        <TextView
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="@android:color/white"
            android:textSize="30sp"/>

        <TextView
            android:id="@+id/date"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textColor="@android:color/white"
            android:textSize="18sp"/>
    </LinearLayout>
</android.support.v7.widget.CardView>

```

## Adapter Implementation with Click Handling

The `MainAdapter` class extends `RecyclerView.Adapter` and demonstrates the ViewHolder pattern essential for efficient list rendering. It manages a mutable list of `Item` objects retrieved from `ItemRepository.getAll()`.

Inside `onBindViewHolder`, the adapter implements click handling by storing the data object in the container view's tag and attaching a shared `OnClickListener`. This approach avoids creating new listener instances for every item and provides direct access to the clicked item's data.

```kotlin
class MainAdapter : RecyclerView.Adapter<MainAdapter.ViewHolder>() {

    private val mItems: MutableList<Item> = ItemRepository.getAll()
    private val mOnClickListener = View.OnClickListener { v ->
        val item = v.tag as Item
        item.updatedAt = Calendar.getInstance()
        item.save()
        notifyDataSetChanged()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return ViewHolder(inflater.inflate(R.layout.main_item, parent, false))
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val item = mItems[position]
        val date = item.updatedAt.timeInMillis
        val color = "#" + date.toString().substring(7)

        holder.card.setCardBackgroundColor(Color.parseColor(color))
        holder.title.text = color
        holder.date.text = DateFormat.format("hh:mm:ss", Date(date))

        holder.container.apply {
            tag = item                      // store the data object
            setOnClickListener(mOnClickListener) // handle click
        }
    }

    override fun getItemCount(): Int = mItems.size

    fun add() {
        val item = Item()
        mItems.add(0, item)
        item.save()
        notifyItemInserted(0)
    }

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val card: CardView = view.findViewById(R.id.card)
        val container: LinearLayout = view.findViewById(R.id.container)
        val title: TextView = view.findViewById(R.id.title)
        val date: TextView = view.findViewById(R.id.date)
    }
}

```

Key implementation details:

- **ViewHolder pattern**: The `ViewHolder` class caches references to `card`, `container`, `title`, and `date` views to eliminate repetitive `findViewById` calls.
- **Click mechanism**: The adapter stores the `Item` object in `holder.container.tag` before attaching `mOnClickListener`, allowing the listener to retrieve the item via `v.tag as Item`.
- **Dynamic updates**: The `add()` method demonstrates how to insert new items at position 0 and notify the adapter with `notifyItemInserted(0)`.

## Activity Setup

The `MainActivity` initializes the RecyclerView with a `LinearLayoutManager` and attaches the `MainAdapter`. It also demonstrates dynamic list modification through the options menu, calling `listAdapter.add()` and scrolling to the top when users select the add action.

```kotlin
class MainActivity : BaseActivity() {
    private lateinit var listAdapter: MainAdapter

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

        findViewById<RecyclerView>(R.id.list).apply {
            setHasFixedSize(true)
            layoutManager = LinearLayoutManager(this@MainActivity)
            listAdapter = MainAdapter()
            adapter = listAdapter
        }
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.main, menu)
        return super.onCreateOptionsMenu(menu)
    }

    override fun onOptionsItemSelected(item: MenuItem?): Boolean {
        listAdapter.add()
        findViewById<RecyclerView>(R.id.list).smoothScrollToPosition(0)
        return true
    }
}

```

## Understanding the Click Handling Pattern

This implementation uses the **view tag mechanism** to associate data with UI elements. In `onBindViewHolder`, the code executes `holder.container.tag = item` to bind the data object directly to the view hierarchy. When a user taps the container, the shared listener retrieves this object through the view's tag property, updates the timestamp, persists changes via `item.save()`, and refreshes the UI with `notifyDataSetChanged()`.

This pattern is memory-efficient because it uses a single `OnClickListener` instance for all items rather than creating anonymous classes within the binding method.

## Summary

- **Location**: Find the complete example in `libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-dbflow/app/src/main/java/mobi/porquenao/poc/kotlin/ui/` within the JetBrains/kotlin repository.
- **Adapter**: The `MainAdapter` demonstrates proper ViewHolder caching and implements click handling via view tags to avoid memory overhead.
- **Layouts**: XML files define a scrollable RecyclerView and clickable CardView items with selectable item backgrounds.
- **Pattern**: Storing data objects in view tags enables efficient item click retrieval without requiring adapter position calculations in the listener.

## Frequently Asked Questions

### How does the RecyclerView adapter handle item clicks in this Kotlin example?

The adapter stores each item object in the container view's tag property during `onBindViewHolder`. A shared `OnClickListener` instance retrieves the item from `v.tag`, allowing direct access to the clicked data without calculating adapter positions or creating new listener objects per row.

### Where can I find the source files for this RecyclerView implementation?

All source files are located in the JetBrains/kotlin repository under `libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kapt2/android-dbflow/app/src/main/java/mobi/porquenao/poc/kotlin/ui/`. This includes [`MainAdapter.kt`](https://github.com/JetBrains/kotlin/blob/main/MainAdapter.kt), [`MainActivity.kt`](https://github.com/JetBrains/kotlin/blob/main/MainActivity.kt), and the corresponding XML layout files in the `res/layout/` directory.

### Why does the adapter use notifyDataSetChanged() instead of notifyItemChanged() in the click listener?

The example uses `notifyDataSetChanged()` for simplicity to refresh the entire list when an item's timestamp updates. In production code, you should prefer `notifyItemChanged(position)` to trigger a single item refresh and maintain animations, but the example prioritizes clarity over optimization.

### Can I use this code in my own Android project?

Yes, you can copy the adapter, activity, and layout files into any Android project using AndroidX or AppCompat dependencies. Note that the example uses `android.support.v7.widget` packages, so you may need to migrate to `androidx` equivalents depending on your project's configuration.