これは 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製)
以上です。