Epoxyとは
EpoxyはRecyclerViewで複雑な画面を構成するためのAndroidライブラリ。
ScrollViewで縦に長い画面をRecyclerViewで楽に管理するのが目的
- Github https://github.com/airbnb/epoxy
- Min SDK 14
どうやって使う?
主に使うのはEpoxyModel
とEpoxyController
モデルはCustomView、xmlレイアウト(DataBinding)から自動生成される。
そのモデルをコントローラーで並べて宣言するだけ。
今回はKotlin + DataBindingを使う方法を説明する。
インストール
公式に従ってapp/build.gradleにライブラリを追加
https://github.com/airbnb/epoxy#installation
dependencies {
// 以下3行のEpoxyライブラリを追加
implementation 'com.airbnb.android:epoxy:3.4.2'
kapt 'com.airbnb.android:epoxy-processor:3.4.2' // Kotlinはkaptを使用
implementation 'com.airbnb.android:epoxy-databinding:3.4.2'
...
- 2019/04/30時点では3.4.2が最新
- epoxy-processorはJavaではannotationProcessor、Kotlinではkaptを使うべし
- epoxy-databinding はDataBindingを連携させるなら追加
EpoxyModelの作り方
今回はDataBindingのみ記載する。
DataBindingの場合、レイアウトxmlから自動でModelを作成するよう記述する。
やる事は以下
- レイアウトxmlをDataBindingで作成
- package-info.java を作成
- 一回ビルド
やることを順に説明する
レイアウトxmlをDataBindingで作成
表示するViewをいつもどおりxmlで作成する。
DataBinding化することを忘れずに。
今回はheader_view.xml
、body_view.xml
、footer_view.xml
を作成した。
package-info.java を作成
package-info.java
を以下の場所に作る
パス
プロジェクト名/app/src/main/java/package-info.java
内容
@EpoxyDataBindingLayouts({R.layout.header_view, R.layout.body_view, R.layout.footer_view})
package com.ikemura.android_kotlin_lab;
import com.airbnb.epoxy.EpoxyDataBindingLayouts;
@EpoxyDataBindingLayouts
にレイアウトxmlを指定すると、Modelが自動生成される。
このファイルを作る時、自分で入力して作ろうとするとIDEが認識せずおかしくなった。
本家からコピペで作ったらやっと認識した。
一体なんだったんだろうか
一回ビルド
レイアウトxmlとpackage-info.javaを作成したら一度ビルドしておく。
このビルドでDataBindingファイルとEpoxyModelが自動生成される。
自動生成されたEpoxyModelは以下
- HeaderViewBindingModel_
- BodyViewBindingModel_
- FooterViewBindingModel_
みて分かるとおり、〜BindingModel_
という命名でレイアウトからModelが作られる。
EpoxyControllerの作り方
2パターンある
引数がない時
EpoxyControllerを継承したクラスを作る。
静的画面を作る際に使う
class MainController : EpoxyController() {
override fun buildModels() {
...
}
引数があるとき
引数が1つの場合は
TypedEpoxyController
を継承して、buildModels
メソッドで引数を受け取る。
class MainController : TypedEpoxyController<DummyContent.DummyItem>() {
override fun buildModels(data: DummyContent.DummyItem?) {
}
引数がの数によって継承するクラスを使い分けるようだ。
2つの場合は Typed2EpoxyController
3つの場合は Typed3EpoxyController
4つの場合は Typed4EpoxyController
と4つまでの引数に対応している。
作り方
まずViewを表示するだけの一番シンプルなコード
class MainController : EpoxyController() {
override fun buildModels() {
headerView {
id("header")
}
bodyView {
id("body")
}
footerView {
id("footer")
}
EpoxyControllerを継承し、buildModels内に表示したい順にEpoxyModelを宣言する。
これだけで画面表示は完成している、Epoxyすごい
初見だと上記のControllerを見ても「???」となると思うので軽く説明。
id()
id()
はEpoxyが内部でModelを管理するために必要らしい。
渡された値(今回は文字列)を内部でハッシュコード化して、Modelを識別してるようだ。
ちなみにこのidを指定しないとIllegalEpoxyUsage
というエラーが投げられ、「モデルにidを指定する必要がある」と怒られる。
headerView {}
headerView {}
はなにかというと、Epoxyによって自動生成された拡張関数である。
EpoxyModelKotlinExtensions.kt
が自動生成されており、中身はこんな感じ
inline fun EpoxyController.headerView(modelInitializer: HeaderViewBindingModelBuilder.() -> Unit) {
HeaderViewBindingModel_().apply {
modelInitializer()
}
.addTo(this)
}
拡張関数内では
HeaderViewBindingModel_
に引数で渡された関数を実行し(modelInitializer()のとこ)
addTo(this)
でモデル(HeaderViewBindingModel)にEpoxyControllerを紐づけている。
画面に表示
表示を全てEpoxyに任せるなら、レイアウトxmlにはRecyclerViewだけ設置するだけでよい
そのRcyclerViewのAdapterに、EpoxyControllerを渡すだけ
表示する画面のレイアウトxml
RecyclerViewだけ設置するだけでOK
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
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"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:context=".epoxy.EpoxyFragment"
/>
RecyclerViewにEpoxyControllerを渡す
Activity or Fragment内でEpoxyControllerを渡す
private fun setupEpoxyController() {
val controller = MyEpoxyController() // EpoxyControllerのインスタンス化
recycler_view.adapter = controller.adapter // adapterを渡す
controller.requestModelBuild() // データを渡さない場合はrequestModelBuild、渡す場合はsetDataを使う
}
コメントにも書いてあるが、
データを渡さない場合はrequestModelBuild、渡す場合はsetDataに表示するデータ等を渡す
Epoxyの感想
初めはViewなのかModelなのかごっちゃになって混乱したが、作っていくと「あーなるほどね」と理解できた。
DataBindingの場合はViewModelのようなクラスが自動生成される、というイメージかな。
(〜BindingModel_ ←こんなクラス)
静的な画面でも縦に長くなる場合はEpoxyを使うと楽になるかも。
RecyclerViewと数十行のEpoxyContorollerだけで画面表示を制御できるのは強力だと思う。
ぜひ自分の担当するプロジェクトにも導入してみたい。
参考にしたページ
- 複雑な画面をRecyclerViewで作るEpoxy - Android - まっせぎ blog https://masegi.hatenablog.com/entry/2019/02/24/215211
- EpoxyでRecyclerViewをもっと簡単にする – PicApp Tech Blog https://techblog.picappinc.jp/epoxy%E3%81%A7recyclerview%E3%82%92%E3%82%82%E3%81%A3%E3%81%A8%E7%B0%A1%E5%8D%98%E3%81%AB%E3%81%99%E3%82%8B-9ab0e77b2b5f