🐻‍❄️

Jetpack Compose の Disposable Effect の動作を調べる

2022/02/12に公開

Dispoable Effect とは

DisposableEffect を利用すると Comopsable が退場したときに終了処理を記述できる。

@Composable
@NonRestartableComposable
@Suppress("ArrayReturn")
fun DisposableEffect(
    vararg keys: Any?,
    effect: DisposableEffectScope.() -> DisposableEffectResult
) {
    remember(*keys) { DisposableEffectImpl(effect) }
}

特徴

  • Disposable Effect に入場するときに Key と Effect を渡せる
  • Disposable Effect が退場したときに Effect の onDispose が呼ばれる
  • Disposable Effect に新しい Key が指定された、古い Key の Effect の onDispose が呼ぶ

※ コンポーザブルの入場と退場についてはこちらに記載があるのでわからない方はこちらを参考してください。

lifecycle.png

動作確認

入場と退場したときの動作

以下のような Boolean が変化すると Disposable Effect が入場 or 退場する。また入場 or 退場時にライフサイクルの購読開始 or 購読停止するサンプルを作成してみた。このサンプルを利用して入場したときと退場したときの動作を確認してみる。

サンプル

  • enable が true になったときに Disposable Effect が入場する
  • enable が false になったときに Disposable Effect が退場する
  • Disposable Effect の入場時には Lifecycle の購読を開始して、退場時には Lifecycle の購読を終了する
@Composable
fun DisposableEffectSample() {
    var enable by remember { mutableStateOf(true) }
    var lifecycleState by remember { mutableStateOf("") }
    val lifecycleOwner = LocalLifecycleOwner.current

    if (enable) {
        DisposableEffect(lifecycleOwner) {
            val observer = LifecycleEventObserver { _, event -> lifecycleState = event.name }
            lifecycleOwner.lifecycle.addObserver(observer)
            onDispose {
                lifecycleOwner.lifecycle.removeObserver(observer)
                lifecycleState = "NO OBSERVER"
            }
        }
    }

    Box(modifier = Modifier.fillMaxSize()) {
        Column(
            modifier = Modifier
                .wrapContentSize()
                .align(Alignment.Center)
        ) {
            Text(
                text = lifecycleState,
                style = MaterialTheme.typography.h2,
                modifier = Modifier.align(Alignment.CenterHorizontally)
            )
            Button(
                onClick = { enable = !enable },
                modifier = Modifier.align(Alignment.CenterHorizontally)
            ) {
                Text(text = if (enable) "DISABLE" else "ENABLE")
            }
        }
    }
}

動作確認

enable を true にすると Disposable Effect が入場するので Lifecyle の購読が開始します。enable を false にすると Disposable Effect が退場するので onDispose が呼ばれ Lifecycle の購読が停止します。というように Disposable Effect の入場・退場にあわせて開始・停止するようにな動きになります。

Emulator-2022_02_12_20_33_57-comporess.gif

Key はどのように指定すべきか?

上記のサンプルでは新しい LifecycleOwner が変更された場合には古い LifeycleOwner に登録した Listener の登録を解除しなければならないので Key を LifecycleOwner に設定しています。今回のように Disposable Effect を利用する処理は Listener の登録・解除が必要になるケースが多いかと思います、なので Listner の登録・解除する先のインスタンスを Key にしておくのが解除漏れがなくなるのでベターかなと思います。

参考文献

Discussion