RxJava の Observable と LiveData と ObservableField をいい感じで使おう

[LiveData について勘違いしていたことをいくつか](https://qiita.com/amay077/items/6e1c94305420a41ff7ed) からの続きです。

前記事では LiveData は、

* 購読解除を自動でやってくれるので便利
* DataBinding(=ObservableField)としては使えない
* 最低限の合成しかできないので物足りない

という事を書きました。

今回の記事では、上で挙げた微妙な３つの点を解消すべく、RxJava と LiveData と DataBinding をいい感じで併用してみたいと思います。今回もコードは Kotlin です。

## RxJava with Android DataBinding

RxProperty を使おう！

* [RxPropertyでRxJavaとAndroid Data Bindingを連携する - Qiita](https://qiita.com/k-kagurazaka@github/items/3fc1fc19ea608cac9913)

はい終了。

RxProperty について書くの何度目なんだ、自分。
作者の @k-kagurazaka@github さんにもお世話になりっぱなしだし、サイコーです、大好きです [RxProperty](https://github.com/k-kagurazaka/rx-property-android)、もっと :star2: を！！

``RxProperty<T>`` は基本的には ``Observable<T>``(というか ``Subject<T>``)なのですが、 ``.value`` プロパティで ``ObservableField<T>`` に変換できます。

```kotlin
// MainViewModel.kt
class MainViewModel : ViewModel() {

    // GitHub ユーザー名。EditText.text から双方向(TwoWay)バインドされる。
    val user = RxProperty<String>()

    init {
        user.set("hogehoge")
    }
}
```

```xml:activity_main.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">

    <LinearLayout
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="net.amay077.livedatasample.view.MainActivity"
        android:orientation="vertical">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="GitHub user name"
            android:text="@={viewModel.user.value}"/>  ←-- user.value とすることで ObservableField に！
    </LinearLayout>
</layout>
```

このように レイアウトXMLに、``viewModel.user.value`` と記述するとデータバインディングできちゃいます。上記例ではちゃんと双方向バインディングも効きます。


## RxJava with LiveData

これは 「RxJava の ``Observable<T>`` から ``LiveData<T>`` に変換する拡張メソッド」を作ってやりましょう。

```kotlin
// ObservableExtensions.kt

/**
 * Observable<T> を LiveData<T> に変換
 */
fun <T> Observable<T>.toLiveData() : LiveData<T> {

    return object : MutableLiveData<T>() {
        var disposable : Disposable? = null;

        // ライフサイクルがActiveになったときに購読開始
        override fun onActive() {
            super.onActive()

            // Observable -> LiveData
            disposable = this@toLiveData.subscribe({
                this.postValue(it)
            })
        }

        // ライフサイクルが非Activeになったら購読停止
        override fun onInactive() {
            disposable?.dispose();
            super.onInactive()
        }
    }
}
```

ライフサイクルが非アクティブ(具体的には onPause)になったときに購読停止してあげればきっと大丈夫なはず。

次のような感じで使えます。

```kotlin
// MainActivity.kt
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        ＜いろいろ省略＞

        // RxProperty を LiveData に変換。
        val liveDataUser = viewModel.user.toLiveData()

        // LiveData を購読
        liveDataUser.observe(lifecycleOwner, Observer { 
            editUserName.setTextKeepState(it)
        })
    }
}
```

通常は ``RxProperty.value`` で、DataBinding すればよいと思うんですが、 BindingAdapter を作るのが面倒とか、View側でちょっと手の込んだことをしたい場合には ``.toLiveData()`` で LiveData に変換して、安全な購読管理を享受できます。

## LiveData を直接使った方がよいケース

RxProperty -> LiveData する時の注意点として、値が変更時しか通知されない、というものがあります。
[昨日書いた](https://qiita.com/amay077/items/6e1c94305420a41ff7ed) ように、 LiveData の特性は、同値チェックは特になく値が設定されれば ``onChanged`` を通知するのですが、 RxProperty は「**変更**通知プロパティ」なので(``RxJava 風に言うと distinctUntilChanged なので``)、同じ値を連続で設定しても最初しか通知されません。

そのため、Model->ViewModel->Viewの方向へ、値をただ垂れ流して、View側で受信して何かしたい場合は、LiveData をそのまま使うのがよいでしょう。これは EventBus(Messenger) 的な使い方です。

```kotlin
// MainViewModel.kt
class MainViewModel : ViewModel() {

    // View 側から購読して Toast を表示するための LiveData。
    // 変更通知が必要ない(=EventBus的に使う)なら、LiveData をそのまま使うのがいいんじゃなイカ。
    private val _toast = MutableLiveData<String>()
    val toast : LiveData<String> = _toast

    fun showToast(view:View) {
        toast.set("トーストだよ")
    }
}
```

```kotlin
// MainActivity.kt
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        ＜いろいろ省略＞

        // Toast を表示するために、 toast:LiveData を購読する。
        viewModel.toast.observe(this, Observer { message ->
            Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
        })
    }
}
```

上記の例は、トーストを表示するために ``LiveData<String>`` を使用しています。
他にはダイアログボックスの表示や、画面遷移の要求メッセージを View 側に通知するためには LiveData をそのまま使うのが良いと思います（というかそこを Observable にする必要を感じない）。

## 完成系

[前回](https://qiita.com/amay077/items/6e1c94305420a41ff7ed#%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F%E3%82%A2%E3%83%97%E3%83%AA)、サンプルとして GitHub のリポジトリ一覧を検索するアプリを作っていたんでしたね。

それを、

* DataBinding
* LiveData
* RxJava
* RxProperty

全部使って書いてみたコードがこちら↓です。

* [amay077/LiveDataSample: ViewModel, DataBinding, LiveData, RxJava, RxProperty 全部使ってみたサンプル](https://github.com/amay077/LiveDataSample)

スクリーンショットはこんなの。

![Untitled.gif](https://qiita-image-store.s3.amazonaws.com/0/8227/579172f5-898c-7dac-e8ac-52dd545f1f07.gif)

AAC 時代でも Observable centric な考えでいいんじゃないでしょうか。
図にまとめるとこんな感じです。

![snap.png](https://qiita-image-store.s3.amazonaws.com/0/8227/1bf05d3f-d884-4f56-d56a-3dedc7961a0c.png)

RxProperty が流行らない理由が分からないのです。みなさん使ってみてくださいね！