StateFlow vs SharedFlow
StateFlow vs SharedFlow
코틀린의 코루틴 라이브러리는 여러 수집자(collector) 간에 데이터를 공유하기 위한 두 가지 핫 Flow(hot flow) 타입을 제공합니다. 바로 StateFlow와 SharedFlow입니다. 두 타입 모두 수집자의 활성 여부와 관계없이 값을 방출하지만, 데이터 저장 방식, 중복 처리 방식, 소비자에게 값을 전달하는 방식에서 뚜렷한 차이가 있습니다. 잘못된 타입을 선택하면 이벤트가 유실되거나 불필요한 리컴포지션(Recomposition)이 발생할 수 있으므로, 이 둘의 차이를 정확히 이해하는 것이 매우 중요합니다. 면접에서도 이 주제에 대한 질문이 자주 등장하는데, 단순히 API 차이만 암기하는 것보다는 각 타입이 왜 필요한지 근본적인 설계 의도까지 파악하시는 것이 좋은 답변으로 이어질 수 있습니다.
이번 면접 질문을 통하여 아래 내용들을 학습하실 수 있습니다.
StateFlow가 단일 현재 값을 보유하고 방출하는 원리SharedFlow가 설정 가능한 버퍼링을 통해 이벤트를 브로드캐스트하는 방식StateFlow의 중복 억제(duplicate suppression) 동작과 그에 따른 영향- 상태 관리와 이벤트 브로드캐스팅 요구사항에 따라 두 타입 중 적절한 것을 선택하는 기준
StateFlow
StateFlow는 항상 정확히 하나의 값만 보유하는 특수한 핫 Flow입니다. 생성 시점에 반드시 초기값을 지정해야 하며, 새로운 수집자가 구독하면 현재 값을 즉시 방출합니다. 값을 업데이트하면 기존에 저장된 값이 새 값으로 교체되며, StateFlow는 구조적 동등성(structural equality), 즉 equals()를 사용하여 새 값이 현재 값과 동일한 경우 방출을 억제합니다.
val uiState = MutableStateFlow(UiState.Loading)
// 상태 업데이트
uiState.value = UiState.Success(data)
// 중복 억제: 동일한 값이므로 방출되지 않음
uiState.value = UiState.Success(data)
새로운 수집자는 다음 방출을 기다릴 필요 없이 UiState.Success(data)를 즉시 수신합니다. 이러한 특성 덕분에 StateFlow는 ViewModel에서 화면 상태를 표현하는 표준적인 선택지가 됩니다. value 프로퍼티를 통해 코루틴 컨텍스트 외부에서도 현재 상태에 동기적으로 접근할 수 있으므로, 클릭 핸들러나 생명주기 콜백, 테스트 검증 등 다양한 상황에서 편리하게 활용할 수 있습니다.
StateFlow는 replay = 1로 설정되고 동등성 기반 중복 필터가 적용된 SharedFlow의 서브타입입니다. 이 상속 관계 덕분에 SharedFlow가 기대되는 곳에 StateFlow를 사용할 수 있지만, 그 반대는 성립하지 않습니다. 면접에서 이 관계를 언급하시면 두 타입의 내부 구조를 깊이 이해하고 있다는 좋은 인상을 줄 수 있습니다.
SharedFlow
SharedFlow는 모든 활성 수집자에게 값을 브로드캐스트하는 범용 핫 Flow입니다. StateFlow와 달리 영구적인 현재 값을 보유하지 않으며, 중복 방출도 억제하지 않습니다. emit을 호출할 때마다 모든 수집자에게 해당 값이 전달됩니다.
val events = MutableSharedFlow<UiEvent>()
// 두 방출 모두 수집자에게 전달됨
scope.launch {
events.emit(UiEvent.ShowSnackbar("Saved"))
events.emit(UiEvent.ShowSnackbar("Saved"))
}
replay 매개변수는 새로운 수집자에게 몇 개의 이전 방출값을 재생할지 결정합니다. replay = 0(기본값)이면 구독 이전에 발생한 방출값은 수신할 수 없고, replay = 1이면 가장 최근 방출값 하나가 재생됩니다.