Profile Pic

Iqbal Ahmed

I develop Android Apps along with Backend
and My only LOVE is Kotlin

How to use Epoxy in Android (Part 1)

How to populate a simple list in Epoxy?

3 minute read

Like automation is evolving in a different sector. how it’s evolving in Android. As we know about autogenerated code where we use a bunch of annotations and its auto write code for you with the help of kapt and annotationProcessor We know many plugins which write boilerplate code for you For eg Dagger.

Same we are moving to declarative programming like JetPack Compose and Litho. The same Airbnb changes the way to show the list by using Epoxy. Indeed its a very robust library.

In this post, I am gonna show How can we populate a simple list using Epoxy. In Epoxy, we got 2 core concepts Models and Controllers. Model can be your CustomView, Databinding(XML), Data Class, or ViewHolder. It’s only responsibility to set data or handle CTA. Controller responsibility populate data on the list with the help of Model. Lets jump to coding

Before starting, Add these dependencies in build.gradle

buildscript {
  repositories {
    mavenCentral()
   }
  dependencies {
    
    //....
    
    classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.0'
  }
}

and these dependencies in app/build.gradle

dependencies {
  
  //...
  
  def epoxyVersion="3.11.0"
  implementation "com.airbnb.android:epoxy:$epoxyVersion"
  kapt "com.airbnb.android:epoxy-processor:$epoxyVersion"
}

Let’s try the Simple Example of Model and Controller

1. Show List using Data Class

Here we need a helper class KotlinModel that we can get from epoxy sample or from our source code.

abstract class KotlinModel(
    @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) = object : ReadOnlyProperty<KotlinModel, V> {
        override fun getValue(thisRef: KotlinModel, property: KProperty<*>): V {
            // This is not efficient because it looks up the view by id every time (it loses
            // the pattern of a "holder" to cache that look up). But it is simple to use and could
            // be optimized with a map
            @Suppress("UNCHECKED_CAST")
            return view?.findViewById(id) as V?
                ?: throw IllegalStateException("View ID $id for '${property.name}' not found.")
        }
    }
}

Once we add helper class then we just need to extend our data class and define our layout and all magic happens when we compile our code.

Layout itemdataclass.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="TextView" />
</androidx.constraintlayout.widget.ConstraintLayout>

Epoxy Model: ItemDataClass.kt

class ItemDataClass(val text: String) : KotlinModel(R.layout.itemdataclass) {

    val tv by bind<TextView>(R.id.tv)

    override fun bind() {
        tv.text = text
        tv.setOnClickListener {
            ViewUtils.showToast(it.context, text)
        }
    }

}

Once our data class ready then we can directly use it in Controller. Creating controller, it’s very simple

Epoxy Controller: SimpleDataController.kt

class SimpleDataController : TypedEpoxyController<List<String>>() {
    private val TAG = this::class.java.simpleName

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

Here we have used TypedEpoxyController which is single Type controller, but if you have multiple types which you want to pass in the controller then you can use other classes Typed2EpoxyController, Typed3EpoxyController, and Typed4EpoxyController

And the last step to attach controller in Epoxy Recyclerview

Layout: activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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">

    <com.airbnb.epoxy.EpoxyRecyclerView
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:itemCount="10"
        tools:listitem="@layout/itemdataclass" />
</FrameLayout>

And MainActivity.kt

class MainActivity : AppCompatActivity() {
    val controller by lazy {
        SimpleDataController()
    }

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

        //Step 1: Set Adapter
        rv.adapter = controller.adapter

        //Step 2: Set Controller
        controller.setData(ArrayList<String>().apply {
            repeat(10) {
                add("Item #$it")
            }
        })
    }
}

Congratulations You populated your first list in Epoxy using Dataclass

In this post, we used Kotlin Data Class as an Epoxy Model and Simple Controller,

In the Next post, we gonna use ViewHolder as an Epoxy Model and Instead of creating a separate controller, we gonna use an extension method to populate data on Epoxy RecyclerView.

SourceCode Link: https://github.com/DastanIqbal/EpoxySample/tree/epoxy/dataclass

Happy Coding !!

Say something

Comments

Nothing yet.

Recent posts

Categories

About

I develop Android Apps along with Backend
and My only LOVE is Kotlin