Jetpack ComposeでonResumeやonPauseの処理を書きたい

この記事をシェア
JetpackCompose一問一答

従来、ActivityやFragmentのonResume()onPause()に実装していた処理は、Lifecycleを使ってComposable関数内に実装することができます。

やりたいこと

Jetpack ComposeでUIを構成しているアプリで、アプリがバックグラウンドに移行したりフォアグラウンドに移行したりした時に何らかの処理を行うため、従来のonResume()onPause()に相当するイベントを取得します。

アプリ全体のonResumeonPauseを検出したいのであれば、ルートのActivityにonResume()onPause()を実装するという方法もあります。また、画面遷移をFragmentで実現している場合は、FragmentのonResume()onPause()を使って、画面ごとに実装することもできます。しかし、Navigation Composeを使って一つのActivity・Fragment内で画面遷移を実現している場合に、特定の画面表示中にアプリがフォアグラウンド・バックグラウンドに移行したことを検出したい場合は、これらの方法は使えません。このような場合は、Lifecycleを使います。

サンプル

ソースコードはGitHubにあります。

主な環境は以下の通りです。

  • Kotlin 1.7210
  • Compose Compiler 1.3.2
  • Compose Libraries 1.2.1
  • Material3 1.0.0-rc01
  • Accompanist 0.25.1

ソースコード

実は、Lifecycleイベントを取得するサンプルコードは、Android Developerサイトに紹介されています。ただ、onResumeやonPauseなどのイベントを取得する方法として紹介されているのではなく、「クリーンアップが必要な作用」を実装するためのDisposableEffect()の使用例として載っているので、探すのが難しいです。下記のソースコードは、Googleのサンプルコードを一部変更して使っています。

@Composable
fun ObserveLifecycleEvent(onEvent: (Lifecycle.Event) -> Unit = {}) {
    // Safely update the current lambdas when a new one is provided
    val currentOnEvent by rememberUpdatedState(onEvent)
    val lifecycleOwner = LocalLifecycleOwner.current

    // If `lifecycleOwner` changes, dispose and reset the effect
    DisposableEffect(lifecycleOwner) {
        // Create an observer that triggers our remembered callbacks
        // for sending analytics events
        val observer = LifecycleEventObserver { _, event ->
            currentOnEvent(event)
        }

        // Add the observer to the lifecycle
        lifecycleOwner.lifecycle.addObserver(observer)

        // When the effect leaves the Composition, remove the observer
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
        }
    }
}

ObserveLifecycleEvent()は、イベントを監視する関数です。この関数は汎用的に使いまわしできます。

onEvent引数は、イベント発生時に呼び出すコールバックです。rememberUpdateState()でラップすることによって、ObserveLifecycleEvent()が何度か再コンポーズされた場合でも、最新のonEventラムダが使われるようになります。(そうしないと、DisposableEffect()が実行された時点のonEventラムダが残ってしまうのだと思います。)

LocalLifecycleOwnerを使うと、CompositionLocalの仕組みによって任意のコンポーザブル関数からLifecycleOwnerオブジェクトを取得できます。LifecycleOwnerクラスはlifecycleプロパティ経由で、onResumeなどのイベントを監視できます。

DisposableEffect()は、コンポーザブルに入場した時に処理を呼び出し、コンポーザブルから退場するときにonDisposeに記述した処理を呼び出すことができます。上の例では、コンポーザブルに入場する時にlifecycle.addObserver()を呼び出してイベントの監視を開始し、退場するときにlifecycle.removeObserver()を呼び出してイベントの監視を終了しています。また、DisposableEffect()は引数のキー(上の例ではlifecycleOwner)が変更されたときも、前回のonDisposeを呼び出したうえで新たな処理を呼び出します。ただ今回の例で、実際にlifecycleOwnerが変化するような場合があるのかどうかはよく分かりません。

LifecycleEventObserverでは、イベントを検出したら最新のonEventコールバックをcurrentOnEventオブジェクト経由で呼び出しています。

@Composable
fun LifecycleEventSample() {
    Text(
        text = "LifecycleEventSample",
    )
    ObserveLifecycleEvent { event ->
        // 検出したイベントに応じた処理を実装する。
        when (event) {
            Lifecycle.Event.ON_RESUME -> Log.d("LifecycleEventSample", "On Resume")
            Lifecycle.Event.ON_PAUSE -> Log.d("LifecycleEventSample", "On Pause")
            else -> {}
        }
    }
}

次はObserveLifecycleEvent()を使う側です。こちらは簡単です。コールバックに、検出したイベントに応じた処理を書いてあげればOKです。

イベントはLifecycle.Event形式で渡されます。イベントの種類は、ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROYの6種類があります。

注意点

コンポーザブルに入場し、初回にObserveLifecycleEvent()を呼び出したとき、ON_CREATEON_STARTON_RESUMEの順にイベントが発生します。なんとなく、この関数を呼び出した時点でアプリが起動済みでActivityも起動済みであればON_CREATEなどのイベントは発生しないような気がしますが、実際には発生するので、余分な処理を実行してしまわないように注意が必要です。

また、コンポーザブルから退場するとき、ON_PAUSEON_STOPON_DESTROYの一連のイベントが発生します。アプリが終了するわけではないので、こちらも必要な処理を停止してしまわないよう注意が必要です。

このような特徴があるので、ObserveLifecycleEvent()は、画面全体を構成するコンポーザブル階層に実装するのが良いと思います。そうすることによって、ActivityのonResumeなどのAPIと同じように、画面への出入りに関連したイベントを実装することができます。

JetpackCompose一問一答

Jetpack Compose一問一答

コンテンツは随時追加していきます。

この記事をシェア