Jetpack Compose で非同期処理を行う場合、どっちを使うべきか。
👉 android - Using rememberCoroutineScope() vs LaunchedEffect - Stack Overflow
悩ましい問題です。
2度押しボタン対策3秒待ちで考えてみます。
rememberCoroutineScope()
val scope = rememberCoroutineScope()
var enabled1 by remember { mutableStateOf(true) }
Button(
onClick = {
scope.launch {
enabled1 = false
delay(3000)
enabled1 = true
}
},
enabled = enabled1
) {
Text("Button1")
}
起動
↓
ボタンを表示
↓
ボタンをクリック
↓
CoroutineScope.launch が実行される
↓
enabled1 が false に更新されて3秒開始
↓
ボタンが更新され無効化される
↓
3秒経ったら enabled1 が true に更新される
↓
ボタンが更新され有効化される
@Composable のスコープでは書けない。
Calls to launch should happen inside a LaunchedEffect and not composition
→ @SuppressLint("CoroutineCreationDuringComposition")
実行のタイミングをユーザー操作に直接的に紐付けれる。
LaunchedEffect
var enabled2 by remember { mutableStateOf(true) }
Button(
onClick = {
enabled2 = false
},
enabled = enabled2
) {
Text("Button2")
}
LaunchedEffect(key1 = enabled2) {
if (!enabled2) {
delay(3000)
enabled2 = true
}
}
起動
↓
ボタンを表示
↓
LaunchedEffect が実行される
↓
enable2 が true なので何もしない
↓
ボタンをクリック
↓
enabled2 が false に更新される
↓
ボタンが更新され無効化される
↓
LaunchedEffect が key1 の変更により実行される
↓
enabled2 が false なので3秒開始
↓
3秒経ったら enabled2 が true に更新される
↓
ボタンが更新され有効化される
↓
LaunchedEffect が key1 の変更により実行される
↓
enable2 が true なので何もしない
@Composable スコープで書く。
re/compose か キーの変化 で実行される。
まとめ
SideEffect系 は、今後、苦労することになると思う。
ViewModel を使ったほうが直感的でないか?
どっちみち、実際は、ViewModel → Repository の経路をたどるし。
// Screen-level Composable
val enabled3 by viewModel.enabled
Button(
onClick = {
viewModel.click()
},
enabled = enabled3
) {
Text("Button3")
}
// ViewModel
private val _enabled = mutableStateOf(true)
val enabled: State<Boolean> = _enabled
fun click() {
viewModelScope.launch {
_enabled.value = false
delay(3000) // request to repository suspend function
_enabled.value = true
}
}
肥大化していますよね、その Composable。
StateHolder としての ViewModel も考慮に入れてみるのもいいかもしれません。
👉 【Jetpack Compose】NavBackStackEntry - Composable のライフサイクルと ViewModel の状態を確認する
👉 【Jetpack Compose】 「Layout Inspector Recomposition counts」で re-compose 回数を確認する
👉 【Jetpack Compose】よくあるボタンの有効化/無効化