RoboguiceのEventBusのような機能


Roboguiceはバージョン1から2の頃使っていて、当時は最強と思っていました。今では代替手段もたくさんあり、バージョン3頃からメンテナンスも止まってきているので新しく利用しようとする人も少ないでしょう。(4を作ってから3のメンテと書いてあったけど、そもそも4も作ってないような)

久しぶりにAndroid開発に関わり、Roboguiceにも再び触れて、こんな機能もあるんだと知った機能を記述しておきます。

それは、```EventManager``` です。
[公式ページ](https://github.com/roboguice/roboguice/wiki/Using-Events-in-your-RoboGuice-application)に書いてある機能はうっすら知っていました。が、あまり良い使い道も思いつかず、ほとんど使っていませんでした。

実はこれ、EventBusやObserverとして使えます。

# サンプル

SecondActivityでボタン押下後、Volleyで通信している間にユーザが画面を戻る操作をしても落ちることなく、前の画面＝MainActivityで通知を受けて処理ができます。

ポイントは、

* 利用する```EventManger```に```@com.google.inject.name.Named(DefaultRoboModule.GLOBAL_EVENT_MANAGER_NAME)```を指定すること
*  ```onStart()```,```onStop()``` で、```registerObserver()```,```unregisterObserver```を行う
* 登録するEventListenerを作成すること
* あとは通知を出したいクラスで```fire```メソッドを呼ぶこと

です。

```MainActivity.java
@ContentView(R.layout.activity_main)
public class MainActivity extends RoboAppCompatActivity {

    @Named(DefaultRoboModule.GLOBAL_EVENT_MANAGER_NAME)
    @Inject
    private EventManager globalEventManager;

    @InjectView(R.id.button)
    private Button button;

    private EventListener listener = new EventListener<WeatherRepository.WeatherEventSuccess>() {
        @Override
        public void onEvent(WeatherRepository.WeatherEventSuccess event) {
            Toast toast = Toast.makeText(MainActivity.this, String.format("You got weater. %s", event.getWeather().title), Toast.LENGTH_LONG);
            toast.show();
        }
    };

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

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        globalEventManager.registerObserver(WeatherRepository.WeatherEventSuccess.class, listener);
//        EventBus.getDefault().register(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        globalEventManager.unregisterObserver(WeatherRepository.WeatherEventSuccess.class, listener);
//        EventBus.getDefault().unregister(this);
    }
    // EventBusでやる場合
    public void onEvent(WeatherRepository.WeatherEventSuccess event){
        Toast toast = Toast.makeText(this, String.format("You got weater. %s", event.getWeather().title), Toast.LENGTH_LONG);
        toast.show();
    }
```

```SecondActivity.java
@ContentView(R.layout.activity_second)
public class SecondActivity extends RoboAppCompatActivity {

    @Inject
    private WeatherFacade facade;

    @Named(DefaultRoboModule.GLOBAL_EVENT_MANAGER_NAME)
    @Inject
    protected EventManager globalEventManager;

    @InjectView(R.id.editText)
    private EditText editText;

    @InjectView(R.id.button)
    private Button button;

    // Roboguiceでやる場合
    private EventListener listener = new EventListener<WeatherRepository.WeatherEventSuccess>() {
        @Override
        public void onEvent(WeatherRepository.WeatherEventSuccess event) {
            Intent intent = new Intent(SecondActivity.this, ThirdActivity.class);
            intent.putExtra("weather", event.getWeather());
            startActivity(intent);
        }
    };

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

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                facade.fetchWeahter(editText.getText().toString());
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        globalEventManager.registerObserver(WeatherRepository.WeatherEventSuccess.class, listener);
//        EventBus.getDefault().register(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        globalEventManager.unregisterObserver(WeatherRepository.WeatherEventSuccess.class, listener);
//        EventBus.getDefault().unregister(this);
    }

    // 以下はEventBusでやる場合
    public void onEvent(WeatherRepository.WeatherEventSuccess event){
        Intent intent = new Intent(SecondActivity.this, ThirdActivity.class);
        intent.putExtra("weather", event.getWeather());
        startActivity(intent);
    }
}
```

```WeatherRepository.java
public class WeatherRepository {

    private Context mContext;

    @Named(DefaultRoboModule.GLOBAL_EVENT_MANAGER_NAME)
    @Inject
    protected EventManager globalEventManager;

    @Inject
    public WeatherRepository(Provider<Context> provider) {
        mContext = provider.get();
    }

    public void fetchWeather(String cityCode) {
        String url = "http://weather.livedoor.com/forecast/webservice/json/v1?city=" + cityCode;

        RequestQueue queue = Volley.newRequestQueue(mContext);
        queue.add(new JsonObjectRequest(Request.Method.GET, url,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {

                        try {
                            Weather entity = new Weather();
                            String title = response.getString("title");
                            entity.title = title;
//                            EventBus.getDefault().post(new WeatherEventSuccess(entity));
                            globalEventManager.fire(new WeatherEventSuccess(entity));
                        } catch (JSONException e) {
                            // エラー処理
                        }
                    }
                },

                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        //エラー処理
                    }
                }));


    }

    public class WeatherEventSuccess {

        private Weather mWeather;

        public WeatherEventSuccess(Weather weather) {
            this.mWeather = weather;
        }

        public Weather getWeather() {
            return mWeather;
        }
    }
}
```

volleyのNetworkDispatcher#run()内でブレークポイントを置いて、止まった後に端末で戻ってブレークポイントを外すと試すことができます。

# まとめ

自分でObserverパターンで実装するよりかは楽だけど、EventBusの方が記述量が少なく、簡単です。
Roboguiceをすでに使っていて、少しでもアプリのサイズを小さくしたい(ためにEventBusを入れない)などの理由があれば、使ってみるのも良いでしょう。

# github

https://github.com/ko2ic/Spike-Roboguice3