Jetpack Composeでは、非同期処理を行うために主に以下の3つの方法が使われます: rememberCoroutineScope
、LaunchedEffect
、そしてCoroutineScope.launch
による通常のlaunch
です。
rememberCoroutineScope
-
rememberCoroutineScope
は、Composable関数内で使用可能なCoroutineScope
を返します。これを使うと、そのComposable関数と同じライフサイクルを共有するコルーチンを起動できます。 -
この方法はよくイベントハンドラ内で使われ、例えばユーザーがボタンをクリックした時にバックグラウンド処理を開始したい場合に便利です。
-
rememberCoroutineScope
によって提供されるCoroutineScope
は、Composableが存在する間生存し続け、Composableが再構築されてもキャンセルされません。
val scope = rememberCoroutineScope()
Button(onClick = {
scope.launch {
// 非同期処理
}
})
LaunchedEffect
-
LaunchedEffect
は、特定のキーが変更された時に実行される副作用(サイドエフェクト)をComposable関数内で起動します。キーが変わらなければ副作用は維持されますが、キーが変わると副作用はキャンセルされて新たに起動されます。 -
LaunchedEffect
はComposable関数のライフサイクルに密接に結びついており、Composableが画面から取り除かれると自動的にキャンセルされます。 -
これは初期化処理やデータの読み込みなど、一度だけ実行したい非同期処理に使用されます。
LaunchedEffect(Unit) {
// 一度だけ実行する非同期処理
}
例
以下のcounterの値が変わるたびにLandingScreen内のonTimeoutの内容が"Even"や"Odd"に更新され
3秒のDelayが終わったタイミングで最新のonTimeoutが実行される
@Composable
fun ParentScreen() {
var counter by remember { mutableStateOf(0) }
Button(onClick = { counter++ }) {
Text("Increment")
}
val onTimeout = {
if (counter % 2 == 0) {
println("Even")
} else {
println("Odd")
}
}
LandingScreen(onTimeout = onTimeout)
}
@Composable
fun LandingScreen(onTimeout: () -> Unit) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
// このLaunchedEffectは、onTimeoutの参照が変わるたびに再起動します。
LaunchedEffect(onTimeout) {
delay(3000) // 3秒のディレイ
onTimeout()
}
}
}
CoroutineScope.launch
-
launch
はコルーチンを開始するためにCoroutineScope
内で直接呼び出されます。これは通常、ViewModel
やActivity
、Fragment
など、ライフサイクルを持つコンポーネント内で使用されます。 -
コルーチンのライフサイクルは
CoroutineScope
によって管理され、このスコープは通常、viewModelScope
やライフサイクルスコープ(lifecycleScope
)などに基づいています。 -
これは、
ViewModel
でのデータの読み込みや長期実行タスクなど、UIのライフサイクルとは独立して非同期処理を行いたい場合に適しています。
viewModelScope.launch {
// 長期間実行する非同期処理
}
まとめ
これら3つの方法は、それぞれ異なるシナリオとライフサイクル管理の要件に基づいて非同期処理を実行するためのものです。
-
rememberCoroutineScope
はイベントに基づく動的な起動に使用 -
LaunchedEffect
はComposableのライフサイクルに密接に結びついた副作用に使用 - そして
launch
はViewModelやActivityといったコンポーネントのライフサイクルが管理する長期間実行する非同期処理に使用されます。