Androidはワンツーパンチ 三歩進んで二歩下がる

プログラミングやどうでもいい話

AndroidでEventBusライブラリを使用してコンポーネント間のイベント通知をスッキリ行う

※2017/01/28追記
EventBusはバージョン3にアップデート時に大きな変更がありました。詳しくは公式サイトにて。当エントリは2.x系の記事となります。
EventBus 3 released, now based on @Annotations - Open Source by greenrobot

こちらのエントリのコードをRxJavaで書き換えてみました。興味がございましたらこちらのエントリもご覧ください。
EventBusライブラリを使っていた箇所をRxJavaで書き換えたよ - Androidはワンツーパンチ 三歩進んで二歩下がる



クラス間でイベントの発生を捉える必要がある時に、Interfaceを使ってCallbackのやり取りを書いたりしますが、EventBusというライブラリを使うと便利です。

GitHub - greenrobot/EventBus: Android optimized event bus that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.

このライブラリを使うと、
イベントを発行する側 → イベントオブジェクトを生成してEventBusでポストする
イベントを受け取る側 → イベントオブジェクトを引数にしたメソッドを定義しておくとそれが呼び出される
という流れになります。
イベントオブジェクトは通知したいイベント別に自分で作成します。

詳しい説明は参考にさせていただいたサイト様をご覧ください。
EventBus for Android(本家のスライド)

Android でイベントバスを使う - Qiita
EventBus はどこでつかうべきか - Qiita
サイト様情報ありがとうございます。助かりました♡



EventBusの導入はAndroid Studioを使っているとGradleなので大変簡単です。
http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.greenrobot%22%20AND%20a%3A%22eventbus%22
↑ここで最新のバージョンを確認してbuild.gradleに
compile 'de.greenrobot:eventbus:2.4.0'のように記述します。

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile 'de.greenrobot:eventbus:2.4.0'
}

Eclipseを使っている場合などは
http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.greenrobot%22%20AND%20a%3A%22eventbus%22
からjarをダウンロードします。



このライブラリを使って
・ワーカースレッドからUIスレッドへのイベント通知
・BroadcastReceiver内からFragmentへイベント通知
を試してみたかったので、サンプルを作りました。下記からダウンロードなどできます。


GitHub - sakurabird/Android-MyExamEventBus: Example code using EventBus library

このサンプルでは
・ワーカースレッドからUIスレッドへのイベント通知
 1,画面のボタンを押す
 2,スレッドを生成
 3,スレッド内からEventBusでポスト
 4,Fragment内でイベントをキャッチ
 5,TextViewを更新

・BroadcastReceiver内からFragmentへイベント通知
 1,バッテリー充電のアクションをBroadcastReceiverでキャッチ(何でもよかったので適当)
 2,onReceive()内からEventBusでポスト
 3,Fragment内でイベントをキャッチ
 4,TextViewを更新

という処理を行っています。下記は処理イメージです。詳しくはコードをご覧ください。

初期画面 Hello world!と表示されている。
f:id:sakura_bird1:20150121000828p:plain


「EventBusの動作確認をする」ボタンを押してワーカースレッドからUIスレッドへのイベント通知をした結果
「スレッドからの通知」と表示されている。
f:id:sakura_bird1:20150121000704p:plain


BroadcastReceiverを起動するため給電のUSBケーブルを指してイベント通知をした結果
「BroadcastReceiverからの通知」と表示されている。
f:id:sakura_bird1:20150121000718p:plain



EventBusのスレッドモードについて

EventBusはスレッド間でのやり取りができます。
その場合イベントをキャッチするメソッドをスレッドモードで記述します。

デフォルトでは同一スレッド間でイベントを通知します。↓のようにonEventメソッドに書きます。
これが最も高速です。

public void onEvent(MessageEvent event) {
        log(event.message);
    }


UIスレッドにイベントを通知したい場合は、↓のようにonEventMainThreadメソッドに書きます。

public void onEventMainThread(MessageEvent event) {
        textField.setText(event.message);
    }


onEventBackgroundThreadメソッドを使うとUIスレッド以外から通知した場合は直接通知元と同じスレッドに通知し、UIスレッドから通知した場合はEventBusで一つのスレッドを使いEventBusのイベントを順番に通知していきます。
他のイベント通知を遅らせないようこのメソッドはすぐに終わらせる必要があります。

public void onEventBackgroundThread(MessageEvent event){
        saveToDisk(event.message);
    }


上記onEventBackgroundThreadメソッドは時間のかかる処理に向いてないため、ネットワークアクセスなど時間のかかる処理は、常に別のスレッドに通知するonEventAsyncメソッドを使うとよいでしょう。

public void onEventAsync(MessageEvent event){
        backend.send(event.message);
    }


以上です。