RecyclerViewを簡単に扱うためのライブラリEpoxyの使い方

# 本記事の目的

RecyclerViewを簡単に扱うためのライブラリとしてEpoxyが存在します。
https://github.com/airbnb/epoxy

Epoxyをどうやって使っていくかについて、多くの記事がすでに存在しますが、簡潔なサンプルが見つからず、最初にどうすれば良いのか少し手間取りました。

そのため、本記事では、__かなりシンプルな__サンプルを交えて使い方を紹介していきたいと思います。
その際、MVVMパターンを用いて実装していますのでご了承ください。
また、言語はJavaを使っています。要望があればKotlinでも書きたいと思います。
サンプルコードを以下のリポジトリで公開しています。ご利用ください。
https://github.com/solt9029/EpoxyTutorial/tree/qiita-java-sample/



# DataBindingを有効化

```gradle
dataBinding {
    enabled = true
}
```



# dependenciesの追加

EpoxyとMVVMのために必要なものを追加します。

```gradle
def epoxy_version = "2.19.0"
implementation "com.airbnb.android:epoxy:${epoxy_version}"
implementation "com.airbnb.android:epoxy-databinding:${epoxy_version}"
annotationProcessor "com.airbnb.android:epoxy-processor:${epoxy_version}"
implementation "android.arch.lifecycle:extensions:1.1.0"
```



# layoutファイル

activity_main.xmlは以下のようにします。
RecyclerViewが設置してあるだけの単純なレイアウトです。
adapterは後からデータバインディングしてあげます。

```xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="adapter"
            type="android.support.v7.widget.RecyclerView.Adapter" />
    </data>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        app:adapter="@{adapter}"
        app:layoutManager="android.support.v7.widget.LinearLayoutManager" />

</layout>
```

続いて、RecyclerViewのアイテムのレイアウトファイルを用意します。こちらは、item.xmlという名前にします。
Itemクラスというものがvariableのtypeで使われていますが、こちらは後で作っていくのでご安心ください。

```xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="item"
            type="com.example.shiode.epoxytutorial.Item" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{item.text}" />

    </LinearLayout>
</layout>
```



# Itemクラスを作る

Itemクラスを作ります。
簡潔に、textというStringプロパティだけのクラスです。

```java
package com.example.shiode.epoxytutorial;

public class Item {
    public String text;

    public Item(String text) {
        this.text = text;
    }
}
```



# MainActivity用にViewModelを作る

MainViewModelというクラスを作ります。
こちらには、RecyclerViewに表示するためのリストのみをObservableLiveDataとしてプロパティにしておきます。

```java
package com.example.shiode.epoxytutorial;

import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.ViewModel;

import java.util.ArrayList;
import java.util.List;

public class MainViewModel extends ViewModel {
    public MutableLiveData<List<Item>> list = new MutableLiveData<>();

    public MainViewModel() {
        List<Item> data = new ArrayList<>();
        data.add(new Item("aaa"));
        data.add(new Item("bbb"));
        data.add(new Item("ccc"));

        list.postValue(data);
    }
}
```



# ここからが本題！package-info.javaを作る

package-info.javaというファイルを作って、以下のように記述します。
これは、簡単に言うと、RecyclerViewのアイテムのレイアウトファイルとしてどのXMLファイルを使うのか、というのを伝えてあげています。
これをすると、Epoxyによって__ItemBindingModel___というクラスが自動生成されます。

```java
@EpoxyDataBindingLayouts({R.layout.item})
@PackageModelViewConfig(rClass = R.class)
@PackageEpoxyConfig(
        requireAbstractModels = true,
        requireHashCode = true,
        implicitlyAddAutoModels = true
)
package com.example.shiode.epoxytutorial;

import com.airbnb.epoxy.EpoxyDataBindingLayouts;
import com.airbnb.epoxy.PackageModelViewConfig;
import com.airbnb.epoxy.PackageEpoxyConfig;
```

余談ですが、もしRecyclerViewのアイテムのレイアウトファイルを複数必要！ってなったときには　``` @EpoxyDataBindingLayouts({R.layout.item, R.layout.hoge, R.layout.fuga}) ``` みたいな書き方をしていきます。



# Controllerを作る

Epoxyでは、Controllerというものを通じて、RecyclerViewに何を表示するかを設定していきます。
今回は、リストを全て単純に表示していくだけのシンプルな実装です。

```java
package com.example.shiode.epoxytutorial;

import com.airbnb.epoxy.TypedEpoxyController;

import java.util.List;

public class MainController extends TypedEpoxyController<List<Item>> {
    @Override
    public void buildModels(List<Item> list) {
        int index = 0;
        for (Item item : list) {
            new ItemBindingModel_().item(item).id(index).addTo(this);
            index++;
        }
    }
}
```

``` .item(item) ``` という記述によって、item.xmlファイルのdataとしてitemの情報が渡されています。



# MainActivityを実装して完了！

MainActivityを以下のようにします。

```java
package com.example.shiode.epoxytutorial;

import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;

import com.example.shiode.epoxytutorial.databinding.ActivityMainBinding;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    private MainController controller = new MainController();
    private ActivityMainBinding binding;
    private MainViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        viewModel = ViewModelProviders.of(this).get(MainViewModel.class);

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setAdapter(controller.getAdapter());

        viewModel.list.observe(this, new Observer<List<Item>>() {
            @Override
            public void onChanged(@Nullable List<Item> list) {
                controller.setData(list);
            }
        });
    }
}
```

先ほど作ったControllerですが、getAdapterというメソッドでRecyclerView.Adapterが生成されます。
また、setDataというメソッドを使うことで、さきほどControllerに実装したbuildModelsに従って、RecyclerViewの表示が変更されます。



# 最後に

今回はかなり簡潔なサンプルだったので、Epoxyを使うメリットが薄く感じられたかもしれません。
そう思った方はぜひ、他の詳細に書かれた記事を見てみてください。
実際に複雑なRecyclerViewを使う場合には、DiffUtilを実装する必要があったりします。
また、ロード中にProgressBarを表示する必要があるときなんかは、viewTypeを複数種類も受けたりする必要が出てきて、普通に実装すると大変になってきます。
そういったときにEpoxyを使うと楽なので、ぜひ使っていきましょう！