KotlinでData Bindingをする - 基本編

Kotlinで基本的なData Bindingを行うための手順です。
Kotlinファイルがビルドできるようになっているのが前提です。
Android Studio 2.1における記述です。

# 全体の流れ
1. build.gradleにData Bindingを使うように設定する
2. バインドするモデルクラスを作成する
2. Layoutファイルを編集する
    3. XMLで開き、 `layout`タグを全体の親要素とするよう追加する
    4. `layout`タグの子要素に`data`タグを追加する
        5. これはバインドされるモデルと対応する
    6. バインドしたい属性に`@{モデルの名前.プロパティ}`と書く
7. ビルドし、Bindingクラスを自動生成する
3. アクティビティ内でBindingクラスを使いバインドするモデルクラスのインスタンスを指定する

# GradleでData Bindingを有効にする設定を行う
Moduleのbuild.gradle に下記を設定

## Data Bindingを有効にするための設定
`````
android {
    ....
    dataBinding {
        enabled = true
    }
}
`````

## Kotlin上でもBindingクラスを自動生成できるようにするための設定
````
dependencies {
    ...
    kapt 'com.android.databinding:compiler:1.0-rc5'
}

kapt {
    generateStubs = true
}
````

# バインドするモデルを作成する
Kotlinっぽく[data class](https://kotlinlang.org/docs/reference/data-classes.html)を使ってみます。
基本編として動作を確認するため、このデータクラスを直接バインドする予定です。

```` Book.kt
data class Book(val title: String, val price: Int, val authors: List<Author>)
````

```` Author.kt
data class Author (val name: String)
````

# レイアウトを作成する
## 全体を`<layout>`タグで括る
1. レイアウトファイルをText形式で開き、`<layout>`タグで全体を括る
    2. 下記属性が重複するとビルドエラーになるので、`<layout>`タグの属性のみに存在するようにするため、他は削除する
        *  ```xmlns:android="http://schemas.android.com/apk/res/android"```
2. バインドするモデルを`<data>`タグ内で定義する
このようになる。

````MainActivity.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- 全体を layout で括る -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- layout の子要素に data タグを追加-->
    <!-- name が layoutの中で参照するときの名前に対応
         type は　バインドするモデルクラスのFQNとする -->
    <data>
        <variable
            name="book"
            type="com.example.kotlinsample.model.Book" />
    </data>

    <RelativeLayout
        xmlns:tools="http://schemas.android.com/tools"
      tools:context="com.example.kotlinsample.MainActivity">
      ...省略...
    </RelativeLayout>
</layout>
````

# バインドするWidgetを配置し、どこに何をバインドするかを定義する
1. 適当にバインドするWidgetを配置（今回はTextViewを2つ配置）

````MainActivity.xml
<TextView
    ...
    android:text="@{book.title}"
    android:id="@+id/bookName"
    ....
/>

<TextView
    ....
    android:text="@{book.authors.size() + &quot;人&quot;}"
    android:id="@+id/authorsCount"
    ....
/>
````
* ``@{ }``の中にバインドしたい要素を書く
* dataタグのname属性で定義した名前でバインドするオブジェクトにアクセスができる
* ある程度はxml上で表現できる
    * [公式のExpression Language](https://developer.android.com/topic/libraries/data-binding/index.html?hl=ja#expression_language)を参照


# リビルドして、Bindingクラスを自動生成させる
1. リビルドを実行すると、ここまでの手順を踏んでいれば作成される

# Activity内でバインドを指示する

````MainActivity.kt
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // バインドするデータを作成。今回は手で作成
        val author1 = Author(name = "一郎")
        val author2 = Author(name = "次郎")
        val book = Book(title = "とても良い本", price = 1000, authors = arrayListOf(author1, author2).toList())
        val mainActivityBinding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        mainActivityBinding.book = book
    }
````

最後の行で book に波線が出てエラーメッセージがでるが動作は問題ない。
エラーメッセージは `Cannot access class '....' Check your module classpath ...`
これについては、 [バグ報告されている](https://youtrack.jetbrains.com/issue/KT-12402#u=1463619483291)。

# 確認
1. 実行するとバインドされていることが確認できます

# 参考
* [Data Binding Library](https://developer.android.com/topic/libraries/data-binding/index.html?hl=ja)
* [Kotlinのリファレンス](https://kotlinlang.org/docs/reference/)