[Android]LiveDataでRxのCombineLatestをやる
複数の LiveData を組み合わせようとすると MediatorLiveData を使用することになりますが、
これがボイラープレート山盛りなコードを書かされて非常に使いにくい。
そこで、Rx みたいにお手軽に 2 つの LiveData を組み合わせる方法はないかと探して、ちょうど良さそうな実装が書かれた下記の記事を見つけました。
Combine Results from Multiple Async Requests – Gaurav Goyal – Medium
この記事では、 zip〜 と関数名をつけていますが、Rx 的には zip ではないです。
2 つのストリーム、どちらかに更新があれば、それぞれストリームの最後の値のセットが流れてくるので、Rx 的には Zip でなく、CombineLatest になります。
ReactiveX – Zip operator
ReactiveX – CombineLatest operator
この記事では関数として定義してますが、もっと Rx 的に書けるように LiveData の拡張関数として書いてみました。
fun <A, B> LiveData<A>.combineLatest(b: LiveData<B>): LiveData<Pair<A, B>> {
return MediatorLiveData<Pair<A, B>>().apply {
var lastA: A? = null
var lastB: B? = null
fun update() {
val localLastA = lastA
val localLastB = lastB
if (localLastA != null && localLastB != null)
value = Pair(localLastA, localLastB)
}
addSource(this@combineLatest) {
lastA = it
update()
}
addSource(b) {
lastB = it
update()
}
}
}
これで、LiveData だけで、ログイン画面で ID とパスワードの入力チェックが通ったらログインボタンを有効にする、というような処理もサクッとかけるようになります。