TL;DR
- Promiseは単一イベントを扱うよ!
- Rxは複数イベントの流れ(ストリーム)を扱うよ!
- Rxで逐次処理させたいときは
flatMap()で都度Observableを作っていくよ!
Introduction
RxJava大流行時代,その導入の理由(建前)としてよく語られるのは次のようなものが多い気がする.
-
Promise(っぽいもの
- 複数の逐次 or 並行な非同期処理をいい感じに捌きたい
-
データバインディング(的な
- Modelの変更をいい感じにViewに通知したい
- リスト処理
特に,非同期まわりでつらさMAXになるAndroid界においては,1つ目のPromiseっぽいのが結構需要高い気がしている.ただ,「Rxを使ってPromiseみたいなことができるよ!」と書いてある記事はあっても具体的な考え方等に触れているものはあまり見た記憶が無いので,本稿ではそこに着目していく.
RxとPromise
そもそも「RxとPromiseは扱う対象が異なる」ということを知ってないと混乱を招く.
- Promise / Future
- 「単一の非同期イベント」を扱う
- Rx
- 「複数イベントのストリーム」を扱う
Rxは(順番がある)複数のイベントが次々に流れてくるものを処理していく.また,完了/エラー通知(onComplete/onError)がない限りはそのストリームは無限に続く.Rxになれた人からすれば至極当然であるが,はじめてRxに手を出した人がこれに気付くことができないと無限ストリームを漂流するハメになる.
どうやってRxでPromiseするの?
JSのPromise,jQueryのdeferredやJDeferredに出てくる各種用語や概念っぽいものとの対応はだいたい以下のとおり.
| Promise | Deferred | Rx | |
|---|---|---|---|
| 返り値 | Promise |
deferred.promise() |
Observable |
| 処理完了通知 | resolve() |
resolve() |
onNext() / onComplete()
|
| エラー通知 | reject() |
reject() |
onError() |
| 逐次処理 | then() |
then() |
flatMap() |
「Promiseの代わりにObservableで非同期処理を包んだクラスを作ろう!」みたいなときに気をつけるのは,RxはPromiseと違って複数イベントを扱うものなので「処理の完了(onComplete())」を流さないといけない,ということ.
また,flatMap()についてだが,ググると大体は「flattenとmapを同時にやってくれるやつ!」みたいなのが出てくる.が,Promise的に使いたいときは「Observableを別のObservableに変換する」と考える.mapが単なる値の変換(写像)をするのに対して,flatMapは「値から新しくObservableを生成して放流する」.ちょうどJDeferredのDonePipeに近い感じ(DonePipeは前の結果からあたらしくPromise作って返す).
Rxのトラップ: ストリームを稼働させる
たとえばPromiseやJDeferredなら何もせずとも処理が始まる.一方,Rxの場合はObservableをsubscribe()(購読?)してあげないと処理が始まらない.もしくはObservableをHotなObservableに変換してあげればストリームの強制起動が出来る.このHot/Cold Observableの概念はややこしいが,慣れると何となく感覚で理解できるようになる.『RxのHotとColdについて - Qiita』の解説がかなり分かりやすい.
Conclusion
- Promiseは単一イベントを扱うよ!
- Rxは複数イベントの流れ(ストリーム)を扱うよ!
- Rxで逐次処理させたいときは
flatMap()で都度Observableを作っていくよ!