Edited at

Cold を Hot にできる。そう、Publish ならね。

More than 5 years have passed since last update.

Rx いいよ Rx とか言っておきながら、いままで Cold と Hot の違いについて、ちゃんとわかってませんでしたスイマセン。

そのため、

で作ったサンプルプログラム、盛大にバグってましたorz


Cold な Observable と Hot な Observable

音楽プレーヤ iPod に例えると自分なりにしっくり来ました。

Observable が iPod で、Observer は聴く人。

なんとこの iPod はイヤホンジャックがたくさんあります。

そしてさらにこの iPod はイヤホンを接続するだけで再生が始まり、抜くと停止します。

Cold な iPod では、聴く人がイヤホンを接続すると、音楽が最初から再生されます。

次の人がイヤホンを接続すると、また音楽が最初から再生されます。(最初の人は、再生されなおすわけじゃないよ。)

Hot な iPod では、最初に聴く人がイヤホンを接続すると、音楽が再生され始めます。

次の人が、イヤホンを接続すると、その人は途中から聴くことになります。一つのストリーミング放送をみんなで聴くみたいな。

最後の人がイヤホンを外すと、再生が止まります(この辺はストリーミングと微妙に感覚が異なる、ストリーミングって、聴いてる人が居ようが居まいが流され続けるってイメージだから)。


何が問題か

以上を踏まえた上で、reactive4java で位置を取得し続ける - Qiita で作ったプログラムのどこが問題だったかというと。

位置を聞くために接続をすると、その都度、locMan.requestLocationUpdates が呼ばれているという事です。上記の音楽プレーヤで例えると、player.start() です。

位置情報の取得は、ホントに無限ストリーミングなので、一見問題無さげに見えますが、2つリスナを登録するのは頂けません。(中には複数のリスナを登録できない API もあるでしょう、ありました。それで気づいたんです。)

これは最初の register でのみ locMan.requestLocationUpdates が実行され、2番目以降の register では、observer.next だけが呼ばれるようにしないといけません。

そのためには、register した複数の observer を保持・管理する必要があります。うげー。


そこで Publish ですよ。

.publish() を Observable のおしりにくっつけます。はい、これだけ。本当に。簡単すぎて「いいの?」って思っちゃうくらい。


getCurrectLocationAsHotObservable.java

/**

* 位置を取得し続ける(Hot)
*/

public static ObservableBuilder<Location> getCurrentLocationAsHotObservable(
final Context context, final String provider) {
return ObservableBuilder.from(
getCurrentlocationAsObservable(context, provider)
).publish(); // Cold → Hot へ変換!
}

これだけで、複数の人が位置を聴きに来ても、locMan.requestLocationUpdates が呼ばれるのは1回だけである、Hot な Observable になります。Rx すげえよ Rx!

reactive4java のソースを読んだところ、前述の「複数の observer を保持・管理して、最初だけリスナ登録して、誰もいなくなったらリスナ解除する」みたいな面倒なことを publish の中(正確には observeOn)で行なってくれているようです。

ますます Reactive Extensions が好きになりましたよ。


.NET の Reactive Extensions と reactive4java の違い

.NET の Reactive Extenstions では、Publish は、IConnectableObservable<T> を返すそうです。そして Subscribe しただけでは再生は開始されず、Connect した時に再生されるのだ、とも。

一方、reactive4java では、publish は、普通の Observable<T> を返します。Observable には register(.NET の Subscribe に相当)しかないので、これを呼び出した時に再生が開始されます。

特に reactive4java の挙動で困っていませんが、今後のバージョンアップで .NET 側に合わせられるかも知れません。

ConnecableObservable という interface は既に用意されていますが、使われていないようです。


参考

Rx の神々のみなさんが懇切丁寧に解説してくださってるのに、失敗しないと気づかない自分のバカバカ!