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
、或者.kt
创建cell的layout。推荐使用xml,搭配databinding使用起来更简单。 - 根据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
、time
是layout的定义的databinding
id
用来区分不同类型的Cell,所有的EpoxyModels必须有唯一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)
})
}
通过Controller中设置data,数据将自动在渲染到列表中
总结
通过简单的实例,可以感觉到Epoxy有以下几个好处
- 避免了ViewHolder的使用, 代码更少
- 通过EpoxyController和EpoxyModel,声明式的填充数据到UI,简单直观
- 每次数据更新后,会自动diff最小量刷新UI(类似pagging的功能)
- 配合MvRx使用,实现完整的响应式UI