How to use Epoxy in Android (Part 1)
How to populate a simple list in Epoxy?
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 !!