Jetpack Compose の Launched Effect の動作を調べる
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 に新しいキーが指定されたら、古いキーのコルーチンはキャンセルされ、新しいキーのコルーチンが起動される
※ コンポーザブルの入場と退場についてはこちらに記載があるのでわからない方はこちらを参考してください。
動作確認
入場と退場したときの動作
以下のような 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 になるとコルーチンはキャンセルされるので終了時のトーストは表示されません。
新しいキーが指定されたときの動作
また以下のようなカウント値が変化すると以下のような 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 のときの開始・終了トーストが表示される動きになります。
Discussion