단방향 데이터 흐름에서 일시적 메시지 처리하기
단방향 데이터 흐름에서 일시적 메시지 처리하기
스낵바(Snackbar)와 같은 일시적 UI 메시지는 네트워크 요청 실패나 특정 작업 완료 등 ViewModel 로직에서 발생하는 경우가 많습니다. 단방향 데이터 흐름(Unidirectional Data Flow, UDF) 아키텍처에서는 이러한 메시지를 일회성 이벤트(one-off event)로 발생시키는 것이 아니라, UI 상태의 일부로 표현해야 합니다. ViewModel이 상태에 메시지를 설정하면, UI가 이를 관찰하여 화면에 표시하고, 표시 완료 후 ViewModel에 알려 해당 상태를 초기화하는 방식입니다. 이번 면접 질문을 통하여 아래 내용들을 학습하실 수 있습니다.
- 일시적 메시지를 일회성 이벤트가 아닌 UI 상태로 모델링해야 하는 이유를 설명할 수 있습니다.
- UI 상태에 nullable
userMessage프로퍼티를 두어 스낵바를 표시하는 방법을 구현할 수 있습니다. - ViewModel이 상태를 설정하고, UI가 표시한 뒤 ViewModel에 통지하여 상태를 초기화하는 소비 사이클(consumption cycle)을 이해할 수 있습니다.
Channel이나SharedFlow를 일시적 UI 이벤트에 사용할 때 발생할 수 있는 위험 요소를 파악할 수 있습니다.- 메시지 상태가 변경될 때
LaunchedEffect를 활용하여 스낵바를 표시하는 방법을 적용할 수 있습니다.
이벤트가 아닌 상태로 관리하는 이유
UDF에서 UI는 상태를 기반으로 렌더링되는 함수입니다. 스낵바를 표시해야 한다면, 상태가 이를 반영해야 합니다. 메시지를 UI 상태 data class의 nullable 프로퍼티로 모델링하면 다음과 같은 이점을 얻을 수 있습니다.
- ViewModel에 상태가 보존되므로, 구성 변경(configuration changes)이 발생해도 메시지가 유실되지 않습니다.
- UI는 항상 상태가 지시하는 내용을 렌더링하므로, 동작을 재현할 수 있습니다.
- 이벤트가 발생하는 시점에 UI가 수집 중이 아니어도 메시지가 유실될 위험이 없습니다.
Channel이나 SharedFlow 같은 일회성 이벤트 메커니즘은 타이밍 의존성(timing dependency)을 발생시킵니다. 이벤트가 방출될 때 UI가 수집하고 있지 않으면 이벤트가 유실될 수 있고, 여러 수집자(collector)가 존재하면 의도하지 않은 수집자가 이벤트를 소비할 수도 있습니다. 메시지를 상태로 표현하면 이러한 문제를 근본적으로 해결할 수 있습니다.
실제 프로젝트에서
Channel을 사용하여 스낵바 이벤트를 처리하다가, 화면 회전 시 메시지가 사라지는 버그를 경험하신 분이 적지 않을 것입니다. 이러한 상황이야말로 상태 기반 접근법이 필요한 대표적인 사례입니다.
소비 사이클(Consumption Cycle)
소비 사이클은 다음 4단계로 구성됩니다.
- ViewModel이 UI 상태의
userMessage프로퍼티를 메시지 텍스트로 업데이트합니다. - UI가 상태를 수집하고,
userMessage가null이 아니면 스낵바 표시를 트리거합니다. - 스낵바가 표시된 후 사라지면(dismissed), UI가 ViewModel의
userMessageShown()메서드를 호출합니다. - ViewModel이
userMessage를 다시null로 설정하여, 리컴포지션(Recomposition) 시 스낵바가 다시 나타나는 것을 방지합니다.
이 사이클에서 핵심은 "UI가 메시지를 표시한 뒤 반드시 ViewModel에 통지해야 한다"는 점입니다. 이 단계를 빠뜨리면 구성 변경 시 동일한 스낵바가 반복적으로 나타나는 문제가 발생합니다.