간단히 정리하자면...
https://marco-cattaneo.medium.com/how-to-handle-single-event-in-jetpack-compose-f90b6220e8c8
Toast 등 one time event 처리를 위해서 state만을 사용한다면 recomposition 시 원치 않는 동작(toast가 다시 보인다)이 발생하거나 기본값 처리가 애매하다는 문제점이 있다. 결국 아래 방법이 가장 많이 쓰이는 것 같다.
// Event
sealed class Event {
data class ShowToast(val message: String): Event
}
// ViewModel
private val channel = Channel<Event>()
val channelFlow = channel.receiveAsFlow()
// composable
@Composable
fun <T> ObserveAsEvents(
flow: Flow<T>,
key1: Any? = null,
key2: Any? = null,
onEvent: (T) -> Unit
) {
val lifecycleOwner = LocalLifecycleOwner.current
LaunchedEffect(flow, lifecycleOwner.lifecycle, key1, key2) {
// 앱이 background라면 foreground로 돌아오면 실행
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
// immediate 없으면 이벤트를 잃을 수 있음
withContext(Dispatchers.Main.immediate) {
flow.collect(onEvent)
}
}
}
}
여기서 channel을 사용하는 이유는...
https://medium.com/@nileshg994/android-alarm-manager-a-magical-wake-up-call-a9847f740799
AlarmManager에는 다양한 set 함수가 있는데, 각각 정확도와 배터리 효율에 따라 선택하면 된다. 특히 Doze 모드를 고려해야 한다.