KotlinでData Bindingをする - Observable Object編


# 前提
[基礎編](http://qiita.com/kykomi/items/104905c20242a7ded9ee)の続きとして、Observable Objectを用いたバインドをKotlinで書いてみます。
すでにGradleの設定が済んでおり、Kotlinでバインドができるようになっていることが前提です。

# モデルを作成する
## シンプルなモデルを作成
今回はObservable Objectの例なのでData Classではなく、普通のクラスを使います。これはObservable Objectを用いる場合は他クラスの継承や、アノテーションを付ける必要があるためです。

とりあえずモデルはシンプルに以下のような感じです。

````OrderViewModel.kt
class OrderViewModel(val book: Book) {
    val orderedBook: Book = book
    var count: Int = 0 // あとで変更するので、 var で定義
}
````
なお、Bookクラスなどは[基礎編](http://qiita.com/kykomi/items/104905c20242a7ded9ee)のものを流用しています。

## BaseObservableを継承する
このままではObservableにはなりませんので、`BaseObservable`を継承します。

````OrderViewModel.kt
class OrderViewModel(val book: Book): BaseObservable() {
    val orderedBook: Book = book
    var count: Int = 0
}
````

## 変更の通知を行うための設定をする
ここがキモとなります。
行うべきことは、以下の2点です。
1. プロパティのゲッターにBindableアノテーションの付与
2. セッターで変更の通知を行う

これらは[公式のData Binding Libraryのドキュメント](https://developer.android.com/topic/libraries/data-binding/index.html?hl=ja#observable_objects)にある下記の記述がソースです。

> This is done by assigning a Bindable annotation to the getter and notifying in the setter.

今回はカウント(count)をObserveするために以下のようになります。

アノテーションの付け方やセッターの実装がKotlin特有ですが、ドキュメントを見れば理解できます。ページ下部の参考にリンクを置いておきます。
なお下記コードで`BR`を使っていますが、これは自動で作られます。

````OrderViewModel.kt
class OrderViewModel(val book: Book): BaseObservable() {
    val orderedBook: Book = book

    @get:Bindable
    var count: Int = 0
        set(value) {
            field = value  // 値をセット
            notifyPropertyChanged(BR.count) // 変更を通知
        }
}
````
これでモデル側の実装は完了です。

# レイアウトファイルでバインドを指示する
これはこれまで通りです。今回は`count`をバインドします。
アクティビィとレイアウトは以下のようになります。

````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 = listOf(author1, author2))
        var order = OrderViewModel(book)

        val mainActivityBinding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        mainActivityBinding.order = order
    }
````

````activity_main.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="order"
            type="com.example.kotlinsample.viewmodel.OrderViewModel" />
    </data>
    ...
        <TextView
            ....
            android:text="@{String.valueOf(order.count)}"
            .... 
        />
</layout>
````

# バインドした値を変更してみる
これで完了ですが、動作上はただのデータバインドです。
ここで、プログラムからBindableにしたcountプロパティを変更してみると、動作が確認できます。
適当にボタンを用意して、クリックでcountの値を増減させます。

````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 = listOf(author1, author2))
        var order = OrderViewModel(book)

        val mainActivityBinding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
        mainActivityBinding.order = order

        // プラスとマイナスボタンは適宜用意し、それぞれのクリックでcountを増減させる
        (findViewById(R.id.plusButton) as Button).setOnClickListener { v ->
            order.count += 1
        }

        (findViewById(R.id.minusButton) as Button).setOnClickListener { v ->
            order.count -= 1
        }
    }
````

これで実行すると、プラスとマイナスのそれぞれのボタンのクリックで、カウントのラベルが増減することが確認できます。

# 参考
* [Data Binding Library | Android Developers](https://developer.android.com/topic/libraries/data-binding/index.html?hl=ja#observable_objects)
* [Annotations - Kotlin](https://kotlinlang.org/docs/reference/annotations.html)
* [Properties and Field - Kotlin](https://kotlinlang.org/docs/reference/properties.html)