Model-Contoller間の通知処理をObserver PatternでやっていたのをRxAndroidを使って書き直してみた。

  • 27
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

Model-Controller間の通知処理をObserver Patternを用いている方がそれなりに居ると思います。
僕もObserver Patternを使用しています。

Observer Patternのメリットはいろいろあるのですが、今回はそこはパスします。

ただし、Observer Patternの適用にもデメリットはあります。
それは「ソースが汚くなる」ということです。(主観的な話といえばそうなのですが。。)

たとえば
「Android内のCalendar一覧を取得し、それをもとにEvent一覧を取得し、取得したEvent一覧の始めのタイトルを表示する」
という機能を作るとします。

下記はこれをObserver Patternを用いて実装した場合のControllerです。

MainActivity.java
public class MainActivity extends Activity implements CalendarObserver, EventObserver{

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView) findViewById(R.id.event_name);
        getEventName();
    }

    private void getEventName() {
        CalendarModel calendarModel = CalendarModel.getInstance();
        calendarModel.addObserver(this);
        calendarModel.requestFetchAll(this);
    }

    @Override
    public void onFetchedAllCalendars(ArrayList<Calendar> calendars) {
        CalendarModel.getInstance().deleteObserver(this);

        EventModel eventModel = EventModel.getInstance();
        eventModel.addObserver(this);
        eventModel.requestFetchAll(this, calendars, System.currentTimeMillis());
    }

    @Override
    public void onFetchedAllEvents(ArrayList<Event> events) {
        EventModel.getInstance().deleteObserver(this);
        mTextView.setText(events.get(0).getTitle());
    }

}

中では

1、カレンダーリスト取得依頼をする
2、通知がくる
3、カレンダーリストをもとにイベントリスト取得依頼をする
4、通知が来る
5、イベントリストの始めのイベント名を表示する

という処理をしているのですが、ソースがどうしても汚くなってしまっています。

onFetchedAllCalendars という関数名からその中で「イベントリストの取得依頼をしている」と想像が着く人はまずいませんよね。
関数で分けるべきでないところをぶつ切りにしてしまわないといけなかったり、関数名から処理の内容を想像できるようにしづらかったりするためこういうことがおきます。

やっと前置きが終了です。

今回RxAndroidを使用して書き換えてみました。
下記が書き換え後のソースです。(モデルとかも書き換えています。)

RxActivity.java
public class MainActivity extends Activity {

    private final CompositeSubscription mCompositeSubscription = new CompositeSubscription();

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = (TextView) findViewById(R.id.event_name);

        // カレンダーリストストリームの作成
        Observable<ArrayList<Calendar>> calendarListStream = RxCalendarModel.getInstance().getCalendarListStream(this);
        // イベントリストストリームの作成
        Observable<ArrayList<Event>> eventListStream = calendarListStream.flatMap(new Func1<ArrayList<Calendar>, Observable<ArrayList<Event>>>() {
            @Override
            public Observable<ArrayList<Event>> call(ArrayList<Calendar> calendars) {
                return RxEventModel.getInstance().getEventListStream(MainActivity.this, calendars, System.currentTimeMillis());
            }
        });

        // Subscriptionの登録
        mCompositeSubscription.add(
                eventListStream
               .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(new Action1<ArrayList<Event>>() {
                            @Override
                            public void call(ArrayList<Event> events) {
                                mTextView.setText(events.get(0).getTitle());
                            }
                        }
                )
        );
    }

    @Override
    protected void onDestroy() {
        mCompositeSubscription.clear();
        super.onDestroy();
    }
}

カレンダーリストのストリームを作って、イベントリストのストリームを作って、Subscriptionを登録するだけ。
しかも、これをぶつ切りにすることなく書く事ができます。
(*ストリームの概念などについてはReactive androidにまとめています。)

上記のようにonDestroyでSubscriptionのclearを行えば、安全性にも問題はありません。
そしてさらに多種のモデルと結合する場合も簡単に書く事ができます。

RxAndroidいいかもしれません。

今回の使用したサンプルは下記で公開しています。
https://github.com/kgmyshin/Observer-Pattern-to-Rx
(MainActivityはObserver Patternを使用しており、RxActivityはRxAndroidで書き換えたものになります。)