Posted at

別プロセスで動いているServiceとHermesEventBusで通信

More than 1 year has passed since last update.

EventBusって便利ですよね。

特に便利さを実感できるのがActivityとServiceで通信したいときだとおもいます。

ほんとうだったら、BroadcastReceiverクラスを作成して、Actionを定義して、、、としないといけないのですが、EventBusだったらregisterして@Subscribeするだけで済みます。

しかし、EventBusで賄えないこともあります。

android:processを使ってServiceが別プロセスで動いているときです。

EventBusは同じプロセス内のクラスにしか届きません。


HermesEventBus

elemers/HermesEventBus

HermesEventBusというライブラリを使えば、プロセス間で通信することができます。

使い方は、以下のような感じ。

HermesEventBus.getDefault().register(this);

HermesEventBus.getDefault().post(new HogeEvent());

このように頭にHermesを付けるだけで、EventBusとほぼ同じように使うことができます。

実際に、別プロセスで動いているServiceに通知できるサンプルコードを作ってみました。


サンプル

通知するイベントは以下のような感じ。

public class GreetEvent {

private String message;

public GreetEvent(String message) {
this.message = message;
}

public String getMessage() {
return message;
}
}


だめな例

まずはふつうにEventBusを使ってみた場合。

最初はServiceです。

EventBusに登録して、@Subscribeを使ったメソッドを定義しておきます。

public class MyService extends Service {

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
EventBus.getDefault().register(this);
return super.onStartCommand(intent, flags, startId);
}

@Subscribe
public void onGreet(GreetEvent event) {
Toast.makeText(this, event.getMessage(), Toast.LENGTH_LONG).show();
}
}

別プロセスで動かすのでマニフェストは以下のようになっています。

 <service

android:name=".MyService"
android:process=".myservice"
... />

android:processを指定しています。

そして、Activityでpostしてみます。

もちろんpostするのはServiceを起動したあとです。

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

...

EventBus.getDefault().post(new GreetEvent("Hello"));
}
}


結果

とうぜん、このコードではServiceはイベントを受け取ることはできません。

EventBusはプロセス間通信には対応していないからです。

では、このコードをHermesEventBusを使うように変更してみましょう。


よい例


初期設定

はじめに、build.gradleに追加しておきましょう。

dependencies {

...

compile 'xiaofei.library:hermes-eventbus:0.3.0'
}

HermesEventBusを使うにはまず、Applicationクラスで初期化する必要があります。

public class MyApplication extends Application {

@Override
public void onCreate() {
super.onCreate();

HermesEventBus.getDefault().init(this);
}
}


ここで少々手続きが必要です。

というのも、HermesEventBusは古いサポートライブラリに依存しているようで、このままだとActionBarActivityが見つからないと言うエラーが発生してしまいます。

対処法は以下の参照先のように、android.support.v7.appパッケージの中に、ActionBarActivityを自分で作っておきます。

package android.support.v7.app;

public class ActionBarActivity extends AppCompatActivity { }

适配新版本support库 · Issue #42 · elemers/HermesEventBus


HermesEventBusに対応させる

あとは、Activity、Serviceの中のEventBusHermesEventBusに置き換えます。

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

...

HermesEventBus.getDefault().post(new GreetEvent("Hello"));
}
}

public class MyService extends Service {

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
HermesEventBus.getDefault().register(this);
return super.onStartCommand(intent, flags, startId);
}

...
}

こんなふうに単純に書き換えるだけです。


結果

toast.png

今度は、Toastが表示されます。

別プロセスでも、Serviceに通知が届いていることが確認できたかと思います。


まとめ

EventButを使った既存のアプリで、Serviceを別プロセスで動かすことになっても、BroadcastReceiverなどを使うよりかは変更する手間は省けます。

もし、どうしても別プロセスで動かさなければならなくなったときは、便利なライブラリですね。