Epoxy RecyclerView Library in Android

Last Updated : 23 Jul, 2025

Implementing a RecyclerView in Android often involves writing a significant amount of boilerplate code, especially when dealing with complex or dynamic lists. This repetitive setup can slow down development and increase errors. To fix this, Airbnb introduced the Epoxy library, which simplifies RecyclerView implementation through a more declarative and composable approach.

Epoxy lets developers create models that represent each item in a RecyclerView. These models include both the data and how the item should be laid out. Instead of writing and managing the RecyclerView adapter manually, you just define what you want to display, and Epoxy handles the rest. It automatically takes care of creating view holders, binding data to views, and calculating the differences between old and new data. This results in cleaner, more maintainable code with less boilerplate and fewer bugs.

Epoxy-RecyclerView-Library-in-Android


Get Started with Epoxy

To get started with the Epoxy library, we need to add a few dependencies. First, navigate to Gradle Scripts > build.gradle.kts (Module :app) and add the following dependencies under the dependencies{} scope.

dependencies {
...
implementation ("com.airbnb.android:epoxy:5.1.4")
implementation ("com.airbnb.android:epoxy-databinding:5.1.4")
implementation ("com.airbnb.android:epoxy-annotations:5.1.4")
kapt ("com.airbnb.android:epoxy-processor:5.1.4")
}

Check for the updated version of the epoxy library from here.

Now, add the kapt plugin (for Kotlin users only) under the plugins{} scope in the same file.

plugins {
...
id ("kotlin-kapt")
}

Finally, add the following line of code in the same file

kapt {
correctErrorTypes = true
}

Components of Epoxy

Epoxy consists of mainly two components:

  1. EpoxyModels
  2. EpoxyController

EpoxyModels

EpoxyModels represent a single item (view) in the Epoxy Recycler View. It is used by Epoxy to determine what views to be displayed and how to bind them with data. These models are immutable and are responsible to bind data to their respective views. There are mainly 2 types of Models:

  1. Generated Models: Epoxy can generate models from custom views (using @ModelView), data binding layouts, or traditional ViewHolder patterns.
  2. Manual Models: You can also define your own models by extending EpoxyModel or its subclasses.

EpoxyController

EpoxyController acts as a bridge between your data and the models (in this case EpoxyModels). It is responsible for generating a list of EpoxyModel instances, which represent the individual items or views to be displayed in the RecyclerView. It listens for data changes (manually or via requestModelBuild()), and automatically rebuilds the model list based on the latest data. Similar to MVVM or MVI patterns, it separates the data/state layer from the UI rendering logic, promoting a clean architecture.

Step by Step Implementation

Step 1: Create a new project

To create a new project in the Android Studio, please refer to How to Create/Start a New Project in Android Studio?

Note: Select Kotlin as the programming language, since this demonstration is shown in Kotlin.

Step 2: Add dependencies for Epoxy Library

Refer to the Get Started with Epoxy section of this article, to know how to add the dependencies

Step 3: Create a Kotlin Helper Model class

Navigate to app > kotlin+java > {package-name}, right click on the folder and select, New > Kotlin Class/File and name the file as KotlinHelperModel.kt. Add the following code to the file.

KotlinHelperModel.kt:

Kotlin
package org.geeksforgeeks.demo

import android.view.View
import androidx.annotation.IdRes
import androidx.annotation.LayoutRes
import com.airbnb.epoxy.EpoxyModel
import kotlin.properties.ReadOnlyProperty

abstract class KotlinHelperModel(
    @LayoutRes private val layoutRes: Int
) : EpoxyModel<View>() {
    private var view: View? = null

    abstract fun bind()

    override fun bind(view: View) {
        this.view = view
        bind()
    }

    override fun unbind(view: View) {
        this.view = null
    }

    override fun getDefaultLayout() = layoutRes

    protected fun <V : View> bind(@IdRes id: Int) =
        ReadOnlyProperty<KotlinHelperModel, V> { _, property ->
            view?.findViewById(id)
                ?: throw IllegalStateException("View ID $id for '${property.name}' not found.")
        }
}


Step 4: Create an layout file for each model

Navigate to app > res > layout and create a layout with the name item_data_class.xml and add the following code.

item_data_class.xml:

XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="TextView" />

</LinearLayout>


Design UI:

design-item-dataclass



Step 5: Create a model class

Create a kotlin file with the name Model.kt and add the following code to the file

Model.kt:

Kotlin
package org.geeksforgeeks.demo

import android.widget.TextView

class Model(
    private val text: String
) : KotlinHelperModel(R.layout.item_data_class) {
    private val tv by bind<TextView>(R.id.tv)

    override fun bind() {
        tv.text = text
        tv.setOnClickListener {
            // handle click
        }
    }
}


Step 6: Create the Controller class

Create a kotlin file with the name Controller.kt and add the following code to the file.

Controller.kt:

Kotlin
package org.geeksforgeeks.demo

import com.airbnb.epoxy.TypedEpoxyController

class Controller() : TypedEpoxyController<List<String>>() {
    override fun buildModels(data: List<String>?) {
        data?.forEachIndexed { index, str ->
            Model(str)
                .id(index)
                .addTo(this)
        }
    }
}


Step 7: Working with MainActivity

Navigate to MainActivity.kt and activity_main.xml and make the following changes.

MainActivity.kt
package org.geeksforgeeks.demo

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.airbnb.epoxy.EpoxyRecyclerView

class MainActivity : AppCompatActivity() {
    // initialize controller
    private val controller by lazy { Controller() }

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

        // set up recycler view
        val recyclerView = findViewById<EpoxyRecyclerView>(R.id.rv)
        // set controller
        recyclerView.adapter = controller.adapter

        // set data to the controller
        controller.setData(List(10) { "Item #$it" })
    }
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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=".MainActivity">

    <com.airbnb.epoxy.EpoxyRecyclerView
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>


Design UI:

design-main


Output:

epoxy-android


Comment

Explore