Java
Android
Kotlin
RxJava

Presenterなどのライフサイクル監視にLifecycleObserverとRxLifecycleを使用した話

More than 1 year has passed since last update.

はじめに

Google IO 2017で、AndroidArchitectureComponentの中の1つでLifecycleObserverが発表されました。
LifecycleObserverは、名前の通りActivityやFragmentなどのライフサイクルイベントを監視し、アノテーションベースで簡単に通知する役割があります。
また、RxLifecycleは、Trelloが作っているRxAndroidのdisposableを管理するライブラリです。自前で、RxJavaなどのdisposableを管理しなければ行けないところを、compose句から簡単に管理できるというところや、指定のイベントからのdisposableが簡単にできるという特徴があります。
詳しい説明とかは、こちらの記事とかがオススメです。
RxAndroid v1.0.0からのライフサイクルへのバインド方法

Presenterのライフサイクル監視

さて、そもそもPresenterのライフサイクルイベントの監視を、みなさんはどうしているでしょうか?
onResumeやonPauseなど、扱うFragmentなどに合わせてそれぞれ用意して、呼ばせているという場合が多いでしょうか?
ただ、それだとこれらの呼び出しを行う基底クラスの作成をしたり、またはそれぞれ地道に呼ぶ場合はコード量がかさんだりとあまりシンプルに解決が難しかったと思います。

そこで登場したのLifecycleObserverです。
これは、FragmentやActivityなどでLifecycleRegistryOwnerを実装することで、LifecycleObserverに対して、ライフサイクルイベントを伝えることができるようになります。
これによって、MVPのPresenterでなくても、ライフサイクルを尊重したいクラスに対して、好きにライフサイクルイベントを付加できることになります。

RxLifecycleObserver

RxLifecycleは、LifecycleProviderを実装したクラスに対してライフサイクルのbindを行うことができるため、今回はLifecycleObserverと、LifecycleProviderを実装したクラスを作ることでLifecycleObserverをRxLifecycleに対応させました。
以下が実際のコードになります。

/**
 * LifecycleObserver convert to Rx
 */
abstract class RxLifecycleObserver : LifecycleProvider<Lifecycle.Event>, LifecycleObserver {
    companion object {
        // For Architecture LifeCycle Binder
        val ARCH_LIFECYCLE = Function<Lifecycle.Event, Lifecycle.Event> { lastEvent ->
            when (lastEvent) {
                Lifecycle.Event.ON_CREATE -> Lifecycle.Event.ON_DESTROY
                Lifecycle.Event.ON_START -> Lifecycle.Event.ON_STOP
                Lifecycle.Event.ON_RESUME -> Lifecycle.Event.ON_PAUSE
                Lifecycle.Event.ON_PAUSE -> Lifecycle.Event.ON_STOP
                Lifecycle.Event.ON_STOP -> Lifecycle.Event.ON_DESTROY
                Lifecycle.Event.ON_ANY -> Lifecycle.Event.ON_DESTROY
                Lifecycle.Event.ON_DESTROY -> throw OutsideLifecycleException("Cannot bind to Architecture lifecycle when outside of it.")
            }
        }
    }

    private val lifecycleSubject = BehaviorSubject.create<Lifecycle.Event>()

    override fun lifecycle(): Observable<Lifecycle.Event> = lifecycleSubject.hide()

    override fun <T : Any?> bindToLifecycle(): LifecycleTransformer<T> = RxLifecycle.bind(lifecycleSubject, ARCH_LIFECYCLE)

    override fun <T : Any?> bindUntilEvent(event: Lifecycle.Event): LifecycleTransformer<T> = RxLifecycle.bindUntilEvent(lifecycleSubject, event)

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    open fun onCreate() {
        lifecycleSubject.onNext(Lifecycle.Event.ON_CREATE)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    open fun onStart() {
        lifecycleSubject.onNext(Lifecycle.Event.ON_START)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    open fun onResume() {
        lifecycleSubject.onNext(Lifecycle.Event.ON_RESUME)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    open fun onPause() {
        lifecycleSubject.onNext(Lifecycle.Event.ON_PAUSE)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    open fun onStop() {
        lifecycleSubject.onNext(Lifecycle.Event.ON_STOP)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    open fun onDestroy() {
        lifecycleSubject.onNext(Lifecycle.Event.ON_DESTROY)
    }
}

GistCode

それぞれ、LifecycleObserverのイベントを、@OnLifecycleEventという形で受け取りつつ、現在のイベントを保持しておくSubjectに値を流していきます。
そして、ARCH_LIFECYCLEで、それぞれのバインドされた際のdisposableの生存期間を決めます。

終わりに

LifecycleObserverは、ActivityとFragmentのライフサイクルイベントをマージした形で受け取っているので、そもそもライフサイクルの管理にはもってこいだと感じました。
また、RxLifecycleの拡張性の高さもあり、非常にいい形にライフサイクルの監視イベントが書けるなと思いました。

ぜひ、みなさんも試してみてください。