これは RxJava Advent Calendar 2017 の7日目の記事です。意外とカレンダーがスカスカしていてRxJava自体の知見はだいぶ出尽くしてしまったのかなという感じですね。
今回はRxRelayというライブラリを紹介しようと思います。
※ RxJavaについての基礎知識はあることを前提とした記事です。
RxRelayとは
- https://github.com/JakeWharton/RxRelay
- Android界隈では神とも呼ばれる、Jake Wharton氏によるRxJava用のライブラリ
- Subjectより安全な、Relayという仕組みを導入するもの
RelayはSubjectから onComplete
と onError
を呼ぶ機能をなくしたもので、つまり onNext
で値を流すことに特化したSubjectということができます。Relayは以下の性質・機能を持っています。
-
Observable
およびConsumer
としてふるまう -
accept
で受け取った値をonNext
に流す - ストリームが終了することはない
-
observable.subscribe(relay)
はDisposableを返すので購読の解除がかんたん -
toSerialized()
を呼ぶことによりスレッドセーフなRelayを生成できる -
AsyncSubject
にあたるAsyncRelay
は存在しない(ストリームの終了がないため)
これらの性質により、Relayは非RxなAPIをRx用のイベントストリームに変換するのに非常に適しています。
Relayの使いどころ
Subjectを使っていて onNext
で値を流しているだけのものはRelayに置き換えてしまうことが可能です。
例えば、RxBindingを使ってMVVMのデータバインディング(AndroidのDataBinding Libraryではないです)を実装しているパターンで、ボタンのクリックイベントをViewModelに伝えたい場合、Subjectで書くと以下のようになります。
class SomeViewModel {
val onButtonClick = PublishSubject.create<Unit>()
}
val viewModel = SomeViewModel()
button.clicks()
.subscribe { viewModel.onButtonClick.onNext(Unit) }
.addTo(...)
これをRelayで置き換えると、
class SomeViewModel {
val onButtonClick = PublishRelay.create<Unit>()
}
val viewModel = SomeViewModel()
button.clicks()
.subscribe(viewModel.onButtonClick)
.addTo(...)
このようにスッキリ書くことができ、 onNext
が排除されてデータバインディングのリアクティブ感もより高まると思います。(個人の感想です)
RxSwiftにも輸入された
RxSwiftにもRxSwift4からRelayが導入されたようです。正確には、Cocoa/UIKitとのバインディングを提供するRxCocoaの方に導入されたのですが、ほぼ標準の機能と言って良いでしょう。
参考記事:
http://tech.mercari.com/entry/2017/12/04/103247
http://tech.connehito.com/entry/variable-is-deprecated
RxJava/RxSwiftで両OS用アプリを開発している身としては非常に助かります
RxJavaもRelayを標準機能として取り入れてもいい気がしました。
追記: RxJSにも
ちょうどこの記事を書いた数日後ですが、RxJS向けのRelayもリリースされていました。(しかもMicrosoft製)
以上です。