【Jetpack Compose/Android】LifeCycleのイベント取得と監視!

【Jetpack Compose/Android】LifeCycleのイベント取得と監視!

この記事からわかること

  • Kotlin/Android Jetpack ComposeLifeCycleとは?
  • ライフサイクルイベント監視取得方法

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

Jetpack Compose自体の基本的な使用方法に関しては以下の記事を参考にしてください。

Composable関数とは

公式リファレンス:Lifecycle of composables

Jetpack ComposeではUIを構築するための関数@Composableアノテーションを付与する設計になっておりこれを「Composable関数」と呼びます。Composable関数では従来のXMLベースのUI構築とは大きく異なり、宣言的にUIを記述できるようになっています。

Composable関数は状態(State)に基づいてUIが描画されます。TextFieldなどがイメージがつきやすいと思いますが、テキスト入力欄の文字列(=状態)の変化イベントを駆動としてComposableが自動的に再コンポーズする流れ(Recomposition)になっています。そして再描画対象となるのはその状態を参照しているUIのみになります。

これまでのActivityやFragmentのライフサイクルとは大きく異なるのがComposable関数の大きな特徴です。

Composableのライフサイクル

Composableのライフサイクルを理解するためにはCompositionという概念の理解が重要です。CompositionとはComposable関数を実行してUIツリーを構築するプロセスのことです。つまり実際にUIが描画されるためのプロセスになり、それをComposable関数が「Compositionに入る」と言ったりします。その後「0回以上再コンポーズ(Recomposition)」され、「Compositionから出る(Disposal)」という一連のイベントで定義されています。

  1. Composition:UIツリーを構築するプロセス。ComposableがUIツリーに「初めて」入る際に生成
  2. Recomposition:監視している状態(State<T> など)の変化に応じて「必要な部分だけ」再描画
  3. Disposal:ComposableがCompositionから外れる。そのStateも破棄される
コンポーザブルのライフサイクルを示す図

引用:Lifecycle of composables

LaunchedEffect

Compositionの変化に紐づく形で使用できるのがLaunchedEffectです。引数にLaunchedEffect識別するためのキー実行したい処理suspend関数で受け取ります。


@Composable
@NonRestartableComposable
@Suppress("ArrayReturn")
@OptIn(InternalComposeApi::class)
fun LaunchedEffect(
    vararg keys: Any?,
    block: suspend CoroutineScope.() -> Unit
) {
    val applyContext = currentComposer.applyCoroutineContext
    remember(*keys) { LaunchedEffectImpl(applyContext, block) }
}

LaunchedEffectComposable関数がCompositionに入ったときにコルーチンを起動します。Compositionから外れると起動していたコルーチンも自動的にキャンセルされ、異なるキーで呼び出すと前のコルーチンはキャンセルされ、新しいコルーチンが起動します。

@Composable
fun UserScreen(vm: UserVm = hiltViewModel()) {

    // Composable関数がCompositionに入ったときにコルーチンを起動
    // キーにUnitを指定すると入場時に一度だけコルーチンを起動させることができる 
    LaunchedEffect(Unit) {
        // この中ではsuspend関数を呼べる
        vm.load()
    }

    DisposableEffect(Unit) {
        vm.startListen()
        onDispose { vm.stopListen() }
    }
}

DisposableEffect

軽く先出ししましたがDisposableEffectComposable関数がCompositionに入ったときと、Compositionから出たときに実行したい処理をコルーチンに含めて起動します。Compositionから外れたタイミングでonDispose内に定義した処理が実行されます。異なるキーで呼び出されると前のonDisposeが実行され、新しいコルーチンが起動します。

@Composable
fun UserScreen(vm: UserVm = hiltViewModel()) {
    // Composable関数がCompositionから出たときにコルーチンを起動
    DisposableEffect(Unit) {
        // リソースの登録・解放に最適
        vm.startListen()
        onDispose { vm.stopListen() }
    }
}

SideEffect

SideEffectComposable関数が再コンポーズ(Recomposition)が終わった直後にコルーチンを起動します。Recompositionが発生するたびに実行されるので状態更新やUI再構築が完了した後に実行したい処理を記載するのに最適です。

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }

    Button(onClick = { count++ }) {
        Text("Clicked $count times")
    }

    SideEffect {
        // Recomposition が完了するたびに呼ばれる
        println("SideEffect: count=$count")
    }
}

定義を確認するとわかりますが、SideEffectsuspend関数は呼び出せないので注意してください。


@Composable
@NonRestartableComposable
@OptIn(InternalComposeApi::class)
fun SideEffect(
    effect: () -> Unit
) {
    currentComposer.recordSideEffect(effect)
}

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

Search Box

Sponsor

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index