코틀린 언어 용어 사전
FlowSharedFlow · hot 스트림 · repeatOnLifecycle

StateFlow

항상 현재 값을 갖는 hot 스트림. 화면 상태에 쓰고, 일회성 이벤트에는 SharedFlow를 쓴다.

항상 현재 값을 하나 갖고 있는 hot 스트림. 화면 상태 관리의 표준이다.

class HomeViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(HomeUiState())
    val uiState: StateFlow<HomeUiState> = _uiState.asStateFlow()

    fun load() = viewModelScope.launch {
        _uiState.update { it.copy(isLoading = true) }
        val items = repository.load()
        _uiState.update { it.copy(isLoading = false, items = items) }
    }
}

cold와 hot의 차이

  • cold (Flow) — 수집자마다 독립적으로 실행된다. 수집 전에는 아무 일도 없다

  • hot (StateFlow) — 수집자와 무관하게 값이 존재한다. 여럿이 같은 값을 공유한다

  • "녹화 영상" 과 "생방송" 의 차이

StateFlow의 성질

  • 초기값이 반드시 필요하다
  • 항상 현재 값을 갖는다 (.value 로 즉시 읽을 수 있다)
  • 새 수집자는 즉시 최신 값을 받는다
  • 같은 값을 다시 넣으면 방출되지 않는다 (conflate + distinctUntilChanged)

마지막 성질이 함정이다 — 같은 값을 다시 보내 화면을 갱신하려 해도 아무 일이 안 일어난다.

상태와 이벤트를 구분한다

  • StateFlow — '상태' — 지금 화면이 어떤 모습인가

    • 회전 후에도 다시 받아야 한다 (최신 값 재전달이 맞다)
  • SharedFlow — '이벤트' — 한 번만 일어나야 하는 일

    • 토스트 · 네비게이션 · 스낵바
    • 재전달되면 화면 회전 시 토스트가 다시 뜬다
private val _events = MutableSharedFlow<UiEvent>()   // replay = 0 (기본)
val events = _events.asSharedFlow()

suspend fun showToast(msg: String) = _events.emit(UiEvent.Toast(msg))

"회전했더니 토스트가 다시 뜬다" 가 이 구분을 안 했을 때의 전형적 증상이다.

안드로이드에서 안전하게 수집한다

// ❌ 화면이 백그라운드로 가도 계속 수집한다 → 자원 낭비 · 크래시
lifecycleScope.launch {
    viewModel.uiState.collect { render(it) }
}

// ✅ STARTED 아래로 내려가면 수집을 멈추고, 돌아오면 다시 시작한다
viewLifecycleOwner.lifecycleScope.launch {
    viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.uiState.collect { render(it) }
    }
}

cold를 hot으로 바꾸기

val users: StateFlow<List<User>> = repository.observeUsers()
    .stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5_000),   // 구독자가 없으면 5초 뒤 중단
        initialValue = emptyList()
    )

WhileSubscribed(5000)이 관용구다 — 화면 회전 같은 짧은 단절에는 유지하고, 진짜로 떠나면 중단한다.

면접 함정

  • "StateFlow는 LiveData의 대체품" → 생명주기 인지가 없다. repeatOnLifecycle이 필요하다.
  • "SharedFlow로 상태를 관리한다" → 현재 값 개념이 없어 화면 상태에는 StateFlow가 맞다.

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — Flow·StateFlow·SharedFlow — 비동기 스트림