🐻‍❄️

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

2022/02/11に公開

Launched Effect とは

Launched Effect は以下のような定義になっておりコルーチンを起動するためのキー(複数)とコルーチンを起動したときに実行する 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) }
}

特徴

  • Launched Effect に入場したときに指定したキーのコルーチンが起動される
  • Launched Effect が退場したときに指定したキーのコルーチンがキャンセルされる
  • Launched Effect に新しいキーが指定されたら、古いキーのコルーチンはキャンセルされ、新しいキーのコルーチンが起動される

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

lifecycle.png

動作確認

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

以下のような Boolean が変化すると Launched Effect が入場 or 退場するようなサンプルを作成してみた。このサンプルを利用して入場したときと退場したときの動作を確認してみる。

サンプル

  • State が true になったときに Launched Effect が入場する
  • State が false になったときに Launched Effect が退場する
  • Launched Effect には開始・終了時にトーストを表示する suspend 関数を渡す
@Composable
fun Toggle() {
    val context = LocalContext.current
    var state by remember { mutableStateOf(false) }

    if (state) {
        LaunchedEffect(Unit) {
            Toast.makeText(context, "start $state", Toast.LENGTH_SHORT).show()

            delay(5000)

            Toast.makeText(context, "end $state", Toast.LENGTH_SHORT).show()
        }
    }

    Box(modifier = Modifier.fillMaxSize()) {
        Column(
            modifier = Modifier
                .wrapContentSize()
                .align(Alignment.Center)
        ) {
            Text(
                text = state.toString(),
                style = MaterialTheme.typography.h1,
                modifier = Modifier.align(Alignment.CenterHorizontally)
            )
            Button(
                onClick = { state = true },
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(8.dp)
            ) {
                Text(text = "TRUE")
            }
            Button(
                onClick = { state = false },
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(8.dp)
            ) {
                Text(text = "FALSE")
            }
        }
    }
}

動作確認

State が ture になったら Launched Effect が入場してコルーチン起動され開始時のトーストが表示されます。coroutines の実行中にState が false にならなければ終了時のトーストが表示されます。もし State が false になるとコルーチンはキャンセルされるので終了時のトーストは表示されません。

toggle_sample.2022-02-11 11_33_03.gif

新しいキーが指定されたときの動作

また以下のようなカウント値が変化すると以下のような Launched Effect に新しいキーが指定されるようなサンプルを作成してみた。このサンプルを利用して新しいキーが指定されたときの動作を確認してみる。

サンプル

  • Launched Effect にはカウント値をキーとして渡す
  • Launched Effect には開始・終了時にトーストを表示する suspend 関数を渡す
@Composable
fun Counter() {
    val context = LocalContext.current
    var count by remember { mutableStateOf(0) }

    Box(modifier = Modifier.fillMaxSize()) {
        Column(
            modifier = Modifier
                .wrapContentSize()
                .align(Alignment.Center)
        ) {
            LaunchedEffect(count) {
                Toast.makeText(context, "start $count", Toast.LENGTH_SHORT).show()

                delay(5000)

                Toast.makeText(context, "end $count", Toast.LENGTH_SHORT).show()
            }
            Text(
                text = count.toString(),
                style = MaterialTheme.typography.h1,
                modifier = Modifier.align(Alignment.CenterHorizontally)
            )
            Button(
                onClick = { count += 1 },
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(8.dp)
            ) {
                Text(text = "INCREMENT")
            }
            Button(
                onClick = { count -= 1 },
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(8.dp)
            ) {
                Text(text = "DECREMENT")
            }
            Button(
                onClick = { count = 0 },
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(8.dp)
            ) {
                Text(text = "ZERO CLEAR")
            }
        }
    }
}

動作確認

まず Increment でカウントアップしてカウント値が1に更新します。すると Launched Effect に 1 がキーとして渡されコルーチンが起動されます。次に Decrement でカウントダウンするとカウント値が 0 に更新します。すると Lauched Effect に 2 がキーとして渡されキーが 1 のときのコルーチンがキャンセルされキーが 0 のときの Coroutiens が起動します。というように動作するのでキーが 1 のときの開始トーストが表示されたあとに続いてキーが 0 のときの開始・終了トーストが表示される動きになります。

counter_sample.2022-02-11 11_33_45.gif

参考文献

Discussion