---
# System prepended metadata

title: airbnb/epoxy

---

# airbnb/epoxy

Epoxyは、RecyclerViewで複雑な画面を構築するためのAndroidライブラリです。Modelは、アノテーションによってカスタムビューまたはデータバインディングレイアウトから自動的に生成されます。Modelは、EpoxyControllerで RecyclerViewに表示するアイテムを宣言するために使用されます。

epoxyによって、ViewHolderの作成や、itemType, itemId, spanCountなどが抽象化され、複数のビュータイプで画面を構築することが簡素化されます。さらに、Epoxyは、ビューステートの保存と差分更新のサポートします。

私たちはAirbnbでEpoxyを開発し、RecyclerViewsでの作業プロセスを簡素化し、必要な機能を追加しました。現在、アプリのほとんどのメイン画面にエポキシを使用しており、開発者のエクスペリエンスが大幅に向上しています。

## インストール

サポートされているビルド構成はGradleだけなので、プロジェクトbuild.gradleファイルに依存関係を追加するだけです。

```
dependencies {
  implementation "com.airbnb.android:epoxy:$epoxyVersion"
  // Add the annotation processor if you are using Epoxy's annotations (recommended)
  annotationProcessor "com.airbnb.android:epoxy-processor:$epoxyVersion"
}
```

Kotlinを使用している場合は、追加する必要があります。

```
apply plugin: 'kotlin-kapt'

kapt {
    correctErrorTypes = true
}
```

`AutoModel`アノテーションが正しく機能するようにします。詳細はこちら。

また、`annotationProcessor`ではなく、`kapt`を使用してください。

## Library Project 

エポキシアノテーションでレイアウトリソースを使用している場合は、ライブラリプロジェクト用にButterknifeのgradleプラグインをに追加します。

```
buildscript {
  repositories {
    mavenCentral()
   }
  dependencies {
    classpath 'com.jakewharton:butterknife-gradle-plugin:10.1.0'
  }
}
```

```
apply plugin: 'com.android.library'
apply plugin: 'com.jakewharton.butterknife'
```

ここで、すべてのepoxyアノテーションでRではなくR2を使用していることを確認してください。
```kotlin
@ModelView(defaultLayout = R2.layout.view_holder_header)
public class HeaderView extends LinearLayout {
   ....
}
```

## Basic Usage

epoxyには2つの主要なコンポーネントがあります。

1. `EpoxyModel`: ViewをRecyclerViewでどのように表示するのかを示すモデル
2. `EpoxyController`: データをどのようなModelで表示するのかを制御します

### 実装の流れ

1. Viewの作成
2. Viewと対応するModelの作成
3. Controllerの作成
4. RecyclerViewへのControllerの設定

### モデルの作成

epoxyは、ビューやレイアウトに基づいてモデルを生成します。生成されたモデルクラスは、サフィックスにアンダースコア(_)を付けられ、 EpoxyControllerクラスの中で直接使用します。

#### カスタムビューから

`@ModelView`アノテーションをビューのクラスに追加します。次に、各setterメソッドに「prop」アノテーションを追加して、モデルのプロパティとしてマークします。

```java
@ModelView(autoLayout = Size.MATCH_WIDTH_WRAP_HEIGHT)
public class HeaderView extends LinearLayout {

  ... // Initialization omitted

  @TextProp
  public void setTitle(CharSequence text) {
    titleView.setText(text);
  }
}
```

`HeaderViewModel_`クラスが自動生成されます

#### データバインディングから

Android DataBindingを使用したモデルの作成が可能です。

```xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="title" type="String" />
    </data>

    <TextView
        android:layout_width="120dp"
        android:layout_height="40dp"
        android:text="@{title}" />
</layout>
```

任意のパッケージに`EpoxyDataBindingLayouts`アノテーションを追加したインターフェースを追加し、databindingのレイアウトを設定してください。

```java
package com.airbnb.epoxy.sample;

import com.airbnb.epoxy.EpoxyDataBindingLayouts;

@EpoxyDataBindingLayouts({R.layout.header_view, ... // other layouts })
interface EpoxyConfig {}
```

`HeaderViewBindingModel_`クラスが自動生成されます。

#### ViewHolderから

DataBindingを使用していないxmlからモデルを作成することも可能です。

```java=
@EpoxyModelClass(layout = R.layout.header_view)
public abstract class HeaderModel extends EpoxyModelWithHolder<Holder> {
  @EpoxyAttribute String title;

  @Override
  public void bind(Holder holder) {
    holder.header.setText(title);
  }

  static class Holder extends BaseEpoxyHolder {
    @BindView(R.id.text) TextView header;
  }
}
```

`HeaderModel_`クラスが自動生成されます。

### モデルをコントローラーから使用する

コントローラーには、RecyclerViewで表示する順にモデルを追加します。

コントローラーの`buildModels`メソッドでは、表示するアイテムを宣言します。データが変更された場合は、`requestModelBuild`を呼び出し、`buildModels`をトリガーします。これによってepoxyはモデルの変更を追跡し、ビューを自動的にバインドして更新します。

例として、PhotoControllerではヘッダー、写真のリスト、およびローダー（さらに写真が読み込まれている場合）を示します。写真が読み込まれるたびにコントローラーの`setData(photos, loadingMore)`メソッドが呼び出され、`buildModels`が呼び出しがトリガーされるため、新しいデータの状態を表すモデルを構築できます。

```java=
public class PhotoController extends Typed2EpoxyController<List<Photo>, Boolean> {
    @AutoModel HeaderModel_ headerModel;
    @AutoModel LoaderModel_ loaderModel;

    @Override
    protected void buildModels(List<Photo> photos, Boolean loadingMore) {
      headerModel
          .title("My Photos")
          .description("My album description!")
          .addTo(this);

      for (Photo photo : photos) {
        new PhotoModel()
           .id(photo.id())
           .url(photo.url())
           .addTo(this);
      }

      loaderModel
          .addIf(loadingMore, this);
    }
  }
```

#### Kotlinを使用している場合

各モデルの拡張関数が生成されるため、このように記述することができます。


```kotlin
class PhotoController : Typed2EpoxyController<List<Photo>, Boolean>() {

    override fun buildModels(photos: List<Photo>, loadingMore: Boolean) {
        header {
            id("header")
            title("My Photos")
            description("My album description!")
        }

        photos.forEach {
            photoView {
                id(it.id())
                url(it.url())
            }
        }

        if (loadingMore) loaderView { id("loader") }
    }
}
```

### RecyclerViewの設定

```java=
MyController controller = new MyController();
recyclerView.setAdapter(controller.getAdapter());

// Request a model build whenever your data changes
controller.requestModelBuild();

// Or if you are using a TypedEpoxyController
controller.setData(myData);
```

`EpoxyRecyclerView`を使用している場合、より簡単に記述できます。

```java=
epoxyRecyclerView.setControllerAndBuildModels(new MyController());

// Request a model build on the recyclerview when data changes
epoxyRecyclerView.requestModelBuild();
```

#### Kotlin

`Kotlin Extensions`を使用すると、コントローラーの作成が不要になります。

```kotlin=
epoxyRecyclerView.withModels {
        header {
            id("header")
            title("My Photos")
            description("My album description!")
        }

        photos.forEach {
            photoView {
                id(it.id())
                url(it.url())
            }
        }

        if (loadingMore) loaderView { id("loader") }
    }
}
```
