Epoxy
Epoxy helps RecyclerView to implement data loading, UI update and other logic more efficiently through a declarative way, and improve the development efficiency of list scenes.
https://github.com/airbnb/epoxy
Epoxy is an Android library for building complex screens in a RecyclerView - airbnb/epoxy
Development Process
The basic use process of Epoxy:
- Create a cell's layout file
can use.xml
, or.kt
create the layout cell. XML is recommended, it is easier to use with databinding. - Generate EpoxyModel according to cell
, declare layout file in package-info.java, kapt automatically generate EpoxyModel code according to xml, for use by EpoxyRecyclerView - Create EpoxyController
EpoxyController is equivalent to the Adapter of RecyclerView, used to bind data to the UI, and define events such as OnClick - Use EpoxyController to
set EpoxyController to EpoxyRecyclerView to complete the data recording and display of the list
Next, briefly introduce the specific implementation of each step. For example, we need to load the following data in the list:
data class Foo (
var title: String,
var bar: List<Bar>
)
data class Bar (
var body: String,
var time: String
)
0. gradle
apply plugin: 'kotlin-kapt' // 需要使用kapt
android {
dataBinding {
enabled = true // 使用databinding
}
}
kapt {
correctErrorTypes = true
}
dependencies {
implementation 'com.airbnb.android:epoxy:3.4.2'
kapt 'com.airbnb.android:epoxy-processor:3.4.2'
implementation 'com.airbnb.android:epoxy-databinding:3.4.2'
}
1. cell layout
list_cell_a.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
>
<data>
<variable
name="title"
type="String"
/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{title}"
android:textSize="24sp"
android:textStyle="bold"
tools:text="test"
/>
</LinearLayout>
</layout>
list_cell_b.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
>
<data>
<variable
name="body"
type="String"
/>
<variable
name="time"
type="String"
/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{body}"
android:textSize="20sp"
tools:text="test"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{time}"
android:textSize="18sp"
tools:text="test"
/>
</LinearLayout>
</layout>
2. package-info.java
@EpoxyDataBindingLayouts({
R.layout.list_cell_a,
R.layout.list_cell_b
})
package com.airbnb.epoxy.sample;
import com.airbnb.epoxy.EpoxyDataBindingLayouts;
After compilation, it will generate EpoxyModels
code according to the layout file , such as ListCellABindingModel_
, ListCellBindingModel_
etc., to bind data
3. EpoxyController
Inherit TypedEpoxyController
, rewrite buildmodels
, and populate UI data in a declarative way.
class FooBarController : TypedEpoxyController<Foo>() {
override fun buildModels(foo: Foo) {
ListCellABindingModel_()
.title(foo.title) // databinding
.id(modelCountBuiltSoFar)
.addTo(this)
foo.bar.forEach {
ListCellBindingModel_()
.body(it.body)
.time(it.time)
.id(modelCountBuiltSoFar)
.addTo(this)
}
}
}
- Choose different base classes according to the number of buildModels parameters, such as
Typed2EpoxyController
,Typed3EpoxyController
etc. title
,body
,time
Is defined layout ofdatabinding
id
Used to distinguish different types of Cell, all EpoxyModels must have a unique id
4. use in RecyclerView
class FooBarFragment : Fragment() {
lateinit var binding: FragmentFooBarBinding //fragment的layout生成的daabinding
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_foo_bar, container, false)
return binding.root
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val controller = FooBarController()
binding.recyclerView.adapter = controller.adapter
val data = Foo("title", listOf(Bar("str1","time1"),Bar("str2","time2")))
controller.setData(data)
})
}
By setting data in the Controller, the data will be automatically rendered in the list
to sum up
Through a simple example, you can feel that Epoxy has the following benefits
- Avoid the use of ViewHolder, less code
- Through EpoxyController and EpoxyModel, declaratively fill data to UI, simple and intuitive
- After each data update, the UI will be automatically refreshed with minimum diff (similar to pagging function)
- Use with MvRx to achieve a complete responsive UI