LoginSignup
10
10

More than 5 years have passed since last update.

Ottoを使ってて気づいたこと

Posted at

Ottoを使い始めて随分経ちました。特にActivityとFragmentとService間のイベント通知手段として大分助かってますが幾つか気づいた点もありました。

1. Androidでは実行時のスレッドに注意

お約束ですがUIに対する変更はMain Thread以外では出来ません。

ThreadEnforcerで実行できるスレッドをチェックできますが面倒くさい場合は下のようなBusの拡張クラス(AndroidBus)を使うといいと思います。(このコードはどこかからのパクリですが元ソースが見つかりませんでしたm(_ _)m)

BusHolder.java
public class BusHolder {
    private static final Bus sBus = new AndroidBus();

    public static Bus getInstance() {
        return sBus;
    }
}
AndroidBus.java
public class AndroidBus extends Bus {
    private final Handler mHandler = new Handler(Looper.getMainLooper());

    @Override
    public void post(final Object event) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            super.post(event);
        } else {
            // force to run post() on main thread
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    post(event);
                }
            });
        }
    }
}

2. 親クラスで定義した@Subscribeは登録されない

公式サイトにも

Unlike the Guava event bus, Otto will not traverse the class hierarchy and add methods from base classes or interfaces that are annotated. This is an explicit design decision to improve performance of the library as well as keep your code simple and unambiguous.

ってありますがパフォーマンスの改善とわかりやすさを目的に継承しているクラスやインターフェースで定義されているアノテーションは見ないようになってます。

といっても特定のSubscriberの処理を共通化する場合があると思いますのでその場合は下のようにして回避できます。


public class Foo extends Fragment {
    public void onHoge(HogeEvent ev) {
        // TODO implement
    }
}

public class Bar extends Foo {
    protected void onStart() {
        super.onStart();
        // BusHolder is a singleton of a Bus instance
        BusHolder.getInstance().register(this);
    }

    protected void onStop() {
        BusHolder.getInstance().unregister(this);
        super.onStop();
    }

    @Subscribe
    @Override
    public void onHoge(HogeEvent ev) {
        super.onHoge(ev);
    }
}


3. Subscriber内でFragmentTransaction#commit()を実行するとIllegalStateExceptionで落ちる場合があります

Ottoに限らずですがFragment#onSaveInstanceState()以降の状態でFragmentTransaction#commit()を呼ぶと

Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

で落ちます。

Ottoの場合はFragment#onStart()でBus#register()してFragment#onStop()でBus#unregister()するのが一般的ですがonStop()は onSaveInstanceState()の後 に実行されるので運が悪いと落ちます。

自分では気づかなくてもCrashlytics等でクラッシュを収集していると思った以上に出ます。

Subscriber内ではFragmentTransaction#commitAllowingStateLoss() を使うのが無難だと思います。

4. 引数を再利用する

最初は

BusHolder.getInstance().post(new HogeEvent());

みたいな事をやってたんですがわざわざ空インスタンスを作るのは勿体無いのでインスタンスに可変の変数を持たせる必要がない場合はEnumを使うようにしました。

enum HogeEvent {
    FOO, BAR, BAZ

    // 必要に応じて固定の変数をもたせるのも可能
}

BusHolder.getInstance().post(HogeEvent.FOO);
10
10
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10