この記事は、 Android Advent Calendar 2017 - Qiita 11日目の記事です。
RecyclerViewで複雑な画面を作りたい!そんな欲求を持っている人が多いと思います。僕もそうです。でも、1個や2個のViewTypeならまだしもたくさんのViewTypeがある場合、getItemViewTypeとかで頑張った結果つらいコードになる未来が見えます。というか見てきました。
Epoxy というアプローチ
Airbnbが作ったRecyclerViewで複雑な画面を作るためのライブラリです。
ModelをCustomViewやDataBinding等から自動生成し、それらを操作するControllerを書き、そのControllerをEpoxyRecyclerViewというクラスにセットする感じです。
具体的に出来ることは、READMEに書かれてある通りなのですが、こういう事が出来ます。
This abstracts the boilerplate of view holders, diffing items and binding payload changes, item types, item ids, span counts, and more, in order to simplify building screens with multiple view types. Additionally, Epoxy adds support for saving view state and automatic diffing of item changes.
ワオ!便利!
使ってみる
サンプルアプリがあったので、それのコードを読んでいきたいと思います。
epoxy/epoxy-sample at master · airbnb/epoxy · GitHub
こういう動きをするアプリです。
これら全ての動作を全部追いかけると大変なので、今回は、DataBindingを利用しているAdd, Clearなどのボタンにフォーカスを当てたいと思います。 このような動きをする部分です。
Modelを作る
今回のサンプルアプリでDataBindingは、 button.xml で利用されています。このbutton.xmlは、リスト上にあるAdd, Clearなどを行うボタンを指しています。
epoxy/button.xml at d2e298902e64a5b634e9932ee2f16f56abfa52bd · airbnb/epoxy · GitHub
DataBindingを利用してるViewのModelを自動生成する場合は、package-info.java
で@EpoxyDataBindingLayouts
を利用して、Modelを自動生成することを宣言する必要があります。
epoxy/package-info.java at a46ed6c6c459f4d102a63d15aceb0e13dc5d246b · airbnb/epoxy · GitHub
@EpoxyDataBindingLayouts(R.layout.button) @PackageModelViewConfig(rClass = R.class) package com.airbnb.epoxy.sample; import com.airbnb.epoxy.EpoxyDataBindingLayouts; import com.airbnb.epoxy.PackageModelViewConfig;
これで、Modelの生成が行われ、ButtonBindingModel_
という名前のクラスが生成されます。
Controller を作る
ButtonBindingModel_
は SampleController
というクラスで利用されています。コードを見ると案外シンプルです。
epoxy/SampleController.java at a46ed6c6c459f4d102a63d15aceb0e13dc5d246b · airbnb/epoxy · GitHub
今回のコードを読むにあたって、僕が重要だなと感じたのは、protected void buildModels(List<CarouselData> carousels)
です。
epoxy/SampleController.java at a46ed6c6c459f4d102a63d15aceb0e13dc5d246b · airbnb/epoxy · GitHub
buildModels(List carousels)
このメソッドは、リストのデータが更新されるたびに実行されます。
buildModelsの中では、このようなコードがあり、何を表示するのか?やそのViewを表示するのか?などの操作が行われていることがわかります。
// 表示文言の指定 // Clickしたら、onAddCarouselClicked callbackを実行する addButton .textRes(R.string.button_add) .clickListener((model, parentView, clickedView, position) -> { callbacks.onAddCarouselClicked(); }); clearButton .textRes(R.string.button_clear) .clickListener(v -> callbacks.onClearCarouselsClicked()) .addIf(carousels.size() > 0, this); // データの条件があえばViewを表示する
SampleControllerをEpoxyRecyclerViewにセットする
作成したControllerは、EpoxyRecyclerViewにセットしています。
ここは、RecyclerViewにセットも出来るようですが、EpoxyRecyclerViewを使うことで、シンプルになり更にパフォーマンスのアレコレもやってくれるそうです。
EpoxyRecyclerView · airbnb/epoxy Wiki · GitHub
recyclerView.setController(controller);
セットしているのはこの部分
epoxy/MainActivity.java at a46ed6c6c459f4d102a63d15aceb0e13dc5d246b · airbnb/epoxy · GitHub
あとはデータの更新を行いたい時にcontroller.setData(...)
を呼び出すだけです。
private void updateController() { controller.setData(carousels); }
所感
読んだ部分が簡単過ぎた。
その他のアプローチ
Githubを検索すると色々あるんですが、どれがいいのかというのは正直よくわかりませんでした。それらと比較して自分がメンテナンスするアプリへの導入を検討するといいと思います。
まとめ
RecyclerViewを利用して複雑な画面を作るためのライブラリであるEpoxyのサンプルアプリのコードを読んでみました。
複雑な画面はなるべく作りたくないですが、Epoxyには様々な機能があり、複雑な画面を作るのにとても有効です。作る必要がある時には試してみる価値はあると思います。