Edited at

OttoからRxJavaへの移行ガイド

More than 1 year has passed since last update.

Otto が突然メンテナンス終了したので言われたとおりRxJavaで置き換えてみた。お、いいね、でも移行するならEventBusでいいんじゃないかな、という話


経緯

_人人人人人人人人人_

> 突然のdeprecate <

 ̄Y^Y^Y^Y^Y^Y^Y^Y ̄

スクリーンショット 2016-01-21 11.20.30.png

https://github.com/square/otto/pull/181


RxJava流行っているしRxJavaで似たようなことできるからOttoのメンテナンスやめるね


えー、EventBus とかOttoみたいなpub/subとRxは別物では… と思ったのだが、

スクリーンショット 2016-01-21 11.20.49.png

gfxさんのつっこみとその後のやりとりを見て、言われたとおり参照されている記事を見てOttoを置き換えてみた

Implementing an Event Bus With RxJava - RxBus


実装

OttoのかわりにRxBusというものをつくる。


RxBus

public class RxBus {

private final Subject<Object, Object> mBus =
new SerializedSubject<>(PublishSubject.create());

public RxBus() {
}

public void send(Object o) {
mBus.onNext(o);
}

public Observable<Object> toObservable() {
return mBus;
}

public boolean hasObservers() {
return mBus.hasObservers();
}
}

実体はこれだけ。


  • 中身はただのPublishSubject

  • ただし、スレッドセーフのためにSerializedSubjectを使用している

  • publisherは send() で送る。subscriberは toObservable() を使う

Ottoだと、BusをシングルトンでもらうためにBusProviderをつくっていたが、同じようにProviderをつくる。

public class RxBusProvider {

private static final RxBus BUS = new RxBus();

private RxBusProvider() {
// No instances.
}

public static RxBus getInstance() {
return BUS;
}
}


Publisher

Publisherは、以下のような感じでイベントを送る。Ottoとほぼ同じ。

RxBusProvider.getInstance().send(new SomeEvent());


Subscriber

public class RxBusSubscriberActivity extends Activity {

private CompositeSubscription mCompositeSubscription;

@Override
protected void onResume() {
super.onResume();

mCompositeSubscription = new CompositeSubscription();
mCompositeSubscription.add(
RxBusProvider.getInstance()
.toObservable()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(o -> {
if (o instanceof SomeEvent) {
// イベントが来ました
}
})
);
}

@Override
protected void onPause() {
super.onPause();

// Subscription解除
mCompositeSubscription.unsubscribe();
}



  • RxBusProvider.getInstance().toObservable() で取得したObservableをsubscribeする

  • Activity/Fragmentのライフサイクルにあわせてsubscribe/unsubscribeする


    • Subscriptionを管理せずに RxLifeCycle でbindしてしまうのもあり




おまけ

RxBusProvider.getInstance().hasObservers() でObserverがいるかどうかがわかるので、以下のように「アプリが表示されている場合はプッシュ通知を表示しない」機能が簡単に実装できる。


  • GCMからのプッシュ通知をイベントで送るようにする


    • Activity/Fragmentでこのイベントをsubscribe (onResumeでsubscribe, onPauseでunsubscribe) して、プッシュ通知がきたときになにか処理をする

    • GCMからプッシュ通知を受けたときにBroadcastReceiverでObserverがいるかどうかを確認する。RxBusProvider.getInstance().hasObservers() == true の場合 (=アプリが表示されている場合) はイベントは送るが、プッシュ通知は表示しない



なるほどと思いました。


まとめ


  • Ottoから「RxJavaを使った似たようなもの」への移行は比較的簡単にできそう


    • ただしRxJavaの知識が必要



  • 短期的にはOttoを使い続けるのがいいのではないだろうか


    • 十分枯れてるし



  • 中期的にはEventBusに移行、がいいのではないだろうか


    • 開発メンバーが皆RxJavaをある程度知っているのであればこのRxBusのような実装でも良い気がするがどうなんだろう。やっぱりEventBusでいいんじゃないだろうか




参照記事など

Subjectとは? Hot/Coldとは? などは以下の記事が参考になりました