[Android] 일회성 이벤트 관찰하기 In Compose

윤찬·2025년 8월 4일

Android

목록 보기
13/37

📌 Observing One-Time Events란?

One-Time Event(일회성 이벤트)란, 안드로이드 UI에서 단 한 번만 처리되어야 하는 이벤트를 말합니다.

대표적인 예시로는 다음과 같은 것들이 있습니다:

  • 로그인 성공 시 네비게이션 이동
  • 토스트 메시지 출력
  • 다이얼로그 노출
  • 스낵바 표시

이러한 이벤트들은 한 번만 처리되어야 함에도 불구하고, 안드로이드의 라이프사이클이나 화면 회전 등의 설정 변경(configuration changes)으로 인해 같은 이벤트가 다시 처리되는 문제가 발생할 수 있습니다.

💡 Jetpack Compose에서 One-Time Event 처리하기

Compose에서 일회성 이벤트를 안전하게 처리하기 위해 아래와 같은 유틸리티 컴포저블을 만들 수 있습니다:

@Composable
fun <T> ObserveAsEvents(
    flow: Flow<T>,
    key1: Any? = null,
    key2: Any? = null,
    onEvent: (T) -> Unit
) {
    val lifecycleOwner = LocalLifecycleOwner.current
    LaunchedEffect(lifecycleOwner.lifecycle, key1, key2) {
        lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
            withContext(Dispatchers.Main.immediate) {
                flow.collect(onEvent)
            }
        }
    }
}

📌 주요 포인트

  • LocalLifecycleOwner.current
    → 현재 컴포저블의 라이프사이클을 추적합니다.
    이를 통해 UI가 포그라운드 상태일 때만 이벤트를 수신하도록 할 수 있습니다.

  • LaunchedEffect + 키 값(key1, key2)
    → LaunchedEffect는 키 값이 변경될 때마다 블록을 재시작합니다.
    이로써 동적으로 수집 조건을 제어할 수 있습니다.

  • repeatOnLifecycle(Lifecycle.State.STARTED)
    → 해당 블록은 Lifecycle이 STARTED 상태일 때만 작동하며, DESTROYED 또는 CREATED 상태에서는 자동으로 정지(suspend)됩니다.


⚠️ 문제: 이벤트 유실 가능성

라이프사이클이 STARTED 이전 상태(CREATED, INITIALIZED)이거나 DESTROYED 상태인 경우에는 collect가 작동하지 않습니다.
따라서 이 시점에 ViewModel에서 이벤트가 emit되면 UI는 이를 수신하지 못하고 이벤트가 유실될 수 있습니다.

예:

  • 화면 회전 직후 → 아직 Lifecycle이 STARTED가 아님
  • 이때 ViewModel에서 네비게이션 이벤트 전송 → collect되지 않음 ❌

✅ 해결책: Dispatchers.Main.immediate

이 문제를 방지하기 위해 collect를 다음과 같이 실행합니다:

withContext(Dispatchers.Main.immediate) {
    flow.collect(onEvent)
}

👉 왜 Main.immediate를 쓰는가?

현재 메인 스레드에 있다면 즉시 실행하고,
그렇지 않다면 메인 큐에 가장 앞줄로 추가하여 지연 없이 실행하기 때문입니다.

이렇게 하면 Lifecycle 상태 전환 사이의 미묘한 시점에서 발생한 이벤트도 놓치지 않고 수집할 수 있습니다.


profile
좋은 개발자가 되기까지

0개의 댓글