Epoxy
Epoxy通過聲明式的方式幫助RecyclerView更高效的實作資料加載、UI更新等邏輯,提高清單場景的開發效率。
https://github.com/airbnb/epoxy
Epoxy is an Android library for building complex screens in a RecyclerView - airbnb/epoxy
開發流程
Epoxy的基本使用流程:
-
建立cell的layout檔案
可以使用
、或者.xml
建立cell的layout。推薦使用xml,搭配databinding使用起來更簡單。.kt
-
根據cell生成EpoxyModel
在package-info.java中聲明layout檔案、kapt根據xml自動生成EpoxyModel代碼,供EpoxyRecyclerView使用
-
建立EpoxyController
EpoxyController相當于RecyclerView的Adapter,用來将資料綁定到UI,同時定義OnClick等事件
-
使用EpoxyController
将EpoxyController設定到EpoxyRecyclerView,完成清單的資料記載和顯示
接下來簡單介紹一下每一步的具體實作。例如我們需要在清單中加載下列資料:
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;
編譯後,會根據layout檔案,生成
EpoxyModels
代碼,例如
ListCellABindingModel_
、
ListCellBindingModel_
等,用來綁定資料
3. EpoxyController
繼承
TypedEpoxyController
,重寫
buildmodels
,用聲明式的方式填充UI的資料。
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)
}
}
}
- 根據buildModels參數個數選擇不同基類,例如
、Typed2EpoxyController
等Typed3EpoxyController
-
、title
、body
是layout的定義的time
databinding
-
用來區分不同類型的Cell,所有的EpoxyModels必須有唯一idid
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)
})
}
通過Controller中設定data,資料将自動在渲染到清單中
總結
通過簡單的執行個體,可以感覺到Epoxy有以下幾個好處
- 避免了ViewHolder的使用, 代碼更少
- 通過EpoxyController和EpoxyModel,聲明式的填充資料到UI,簡單直覺
- 每次資料更新後,會自動diff最小量重新整理UI(類似pagging的功能)
- 配合MvRx使用,實作完整的響應式UI