「 DataBinding　やり方 」

# この記事は
今更だけど、`DataBinding`のやり方をまとめます。
実はDataBinding理解できるようになったのつい最近で、いまだに過去の自分の実装を見ながら、おぼつかない手付きでコード書いているので、そろそろQiitaにまとめた方がいいなと思いました。

なーんでこんな覚えられないんだろうな〜。

# DataBindingとは
`DataBinding`とは、**変更されたデータをコードからUI側(View)へ伝える**ためのライブラリです。
似たようなライブラリに`ViewBinding`もあります。
`DataBinding`と`ViewBinding`の違いは[こちら](https://qiita.com/mi_iroha/items/dbc07737e81776e05f8d#%E8%BF%BD%E8%A8%98databinding%E3%81%A8%E3%81%AE%E9%81%95%E3%81%84%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)を参考にしてください。

# DataBindingのやり方
では実際のコードを見つつ、databindingの使い方を見ていきましょう。

## :cat: 概要
例えば、今回は以下のようなプロモーションカードの情報をコードからView側へ伝えることを考えます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/906559/1b9e78b1-9805-9bba-c237-b4bdcc1c36e0.png" width=50%>

画像の下にあるドットインジケータを見ると分かると思いますが、このプロモーションカードは3枚あって、スワイプすると次のプロモーションが見れます。

この実装にあたって`DataBinding`を使う部分のイメージはこんな感じです。
かなりざっくりですが。。
![スクリーンショット 2022-03-29 15.21.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/906559/9afabffd-c806-ca22-4dbd-8f4d30d9b4ec.png)




## :dog: 実践
まずUI側に渡したいデータのデータクラスを作成します。
プロモーションカードは「画像」「画像のタイトル」「サブタイトル」で構成されていて、合計で三つのカードを表示するので`id`も持っている方がいいかもしれません。
なので、今回は以下のようなデータクラスを作成しました。
```Promotion.kt
data class Promotion(
    val id: Int,
    val imageUrl: String,
    val title: String,
    val subTitle: String
)
```

次に、データを表示したいView側にdatabindingの設定をします。
表示したいlayout xmlに移動して、一番上にカーソルをおいて右クリックすると`Show Context Actions`が出てきます。
![スクリーンショット 2022-03-29 15.37.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/906559/205ebf67-874d-ae9c-b34a-b541ac1edb3a.png)

これをクリックすると`Convert to databinding layout`と出てくるので、それを選択します。
![スクリーンショット 2022-03-29 15.37.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/906559/b9521762-c6f7-d0e3-8a70-8d5d4e032d11.png)

そうすると自動で`databinding`の雛形がxmlに導入されます。

あとは`databinding`に`name`と`type`を設定します。
- `name`...コード側から受け取るデータクラスをどのような名前で受け取るか
- `type`...受け取りたいデータクラス

て感じです。

```home_promotion_item.xml
<data>
  <variable
     name="promotion" 
	 type="com.nemo.androiduitraining.entity.Promotion" /> 
</data>
```

次に、表示したい画面(layout xml)の詳細設定を実装するためのclassで、xml側で設定したdatabidingとコード側から渡したいデータをバインド(紐付け)します。

```HomePromotionItem.kt
class HomePromotionItem(
    private val promotion: Promotion,
) : BindableItem<HomePromotionItemBinding>() {
    override fun bind(viewBinding: HomePromotionItemBinding, position: Int) {
	    // viewBinding.[layout側で設定したname] = コンストラクタで受け取ったdataclass
		viewBinding.promotion = promotion
        viewBinding.executePendingBindings()
    }
}
```

これによって、ViewModelで`dataclass`の変更を受け取った場合に、更新されたデータを画面に渡すことができます。

ちなみにViewModelはこんな感じ。
```HomeAllViewModel.kt
@HiltViewModel
class HomeAllViewModel @Inject constructor() : ViewModel() {
    val renderData = MutableLiveData<RenderData>(RenderData(generatePromotionList()))
    data class RenderData(
        val promotionList: List<Promotion>
    )

    private fun generatePromotionList() : List<Promotion> {
        return listOf(
            Promotion(
                1,
                "https://media.wwdjapan.com/wp-content/uploads/2018/09/10101619/180910_parco_01.jpg",
                "私は裸になれない。",
                "みんなそうやろ。"
            ),
            Promotion(
                2,
                "https://m-78.jp/wp-content/uploads/2015/08/amu-02-660x466.jpg",
                "AMU EST",
                "ﾈｺﾁｬｶﾜｲﾚﾁｭﾈﾖﾁﾖﾁﾖﾁﾖﾁ"
            ),
            Promotion(
                3,
                "https://s3-ap-northeast-1.amazonaws.com/statics.pen-online.jp/image/upload/creator/jil-sander-19-aw/jil-sander-19-aw_N0lDkYA.jpg",
                "JIL SANDER",
                "裸アウターで屋上ぼっちはさすがに寒いで"
            )
        )
    }
}
```
ここでは渡したいデータ(プロモーションカードの情報が入っているリスト)を、`RenderData`という名前のデータクラスで管理し、レンダリングしたいデータとリストを紐付けています。紐付けができたら、`RenderData`クラスを`MutableLiveData`を使ってサブスクライブ可能にします。

最後に、更新されたデータをUIのどの位置に表示したいかを設定します。
```home_promotion_item.xml
<ImageView
	  android:id="@+id/promotion_image"
	  android:layout_width="0dp"
	  android:layout_height="0dp"
	  android:scaleType="centerCrop"
	  app:imageUrl="@{promotion.imageUrl}"   // here
	  app:layout_constraintDimensionRatio="W,16:9"
	  app:layout_constraintBottom_toBottomOf="parent"
	  app:layout_constraintEnd_toEndOf="parent"
	  app:layout_constraintStart_toStartOf="parent"
	  app:layout_constraintTop_toTopOf="parent" />
	

<TextView
	  android:id="@+id/promotion_title"
	  android:layout_width="wrap_content"
	  android:layout_height="wrap_content"
	  android:layout_marginStart="20dp"
	  android:layout_marginBottom="8dp"
	  android:text="@{promotion.title}"   // here
	  android:textColor="@color/white"
	  android:textSize="20sp"
	  android:textStyle="bold"
	  app:layout_constraintBottom_toTopOf="@id/promotion_sub_title"
	  app:layout_constraintStart_toStartOf="parent" />

<TextView
	  android:id="@+id/promotion_sub_title"
	  android:layout_width="wrap_content"
	  android:layout_height="wrap_content"
	  android:layout_marginStart="20dp"
	  android:layout_marginBottom="32dp"
	  android:text="@{promotion.description}"   // here
	  android:textColor="@color/white"
	  android:textSize="13sp"
	  app:layout_constraintBottom_toBottomOf="@id/promotion_image"
	  app:layout_constraintStart_toStartOf="parent" />
```

これで、
```
View側のステータスの変化を受け取る
→ データを更新する
→ 更新したデータをViewに表示する(レンダリングする)
```
という一連の流れが実装できました。