본문 바로가기
Android 개발/Coroutine , Flow, Channel

StateFlow vs SharedFlow 를 비교해보자 #이벤트 핸들링

by Developer88 2023. 5. 6.
반응형

오늘은 StateFlow 와 SharedFlow 에 대해서 정리해 보도록 하겠습니다.

 

1. 기존 글 참조

만약 SharedFlow와 StateFlow 각각에 대한 기본적인 부분들에 대해서 정리하고 싶으시다면,

아래 글들을 참조하신 다음에 이 글을 읽으면 더욱 도움이 될 것 입니다.

 

>> SharedFlow 에 대한 총정리 # Buffer Replay tryEmit Kotlin Coroutine

>> mutableStateOf 와 MutableStateFlow 비교 총정리 # collectAsState

 

2. StateFlow 는 State 변화를 위한 API

2-1. StateFlow 는 이벤트핸들링을 위한 API가 아니다

아래는 Kotlin 이 아닌 Android의 공식문서인데요.

중요한 부분이 잘 설명되어 있으니 보도록 하겠습니다.

StateFlow는 flow의 state-holder라고 되어 있고요.

state을 업데이트하기위해서는,

새로운 값은 value property에 넣어주어야 한다고 되어 있습니다.

 

 

 

만약 아래와 같은 시나리오를 생각해 보겠습니다.

  1. 유저클릭
  2. 기존에 정의한 네트워크 flow를 실행해서 데이터 받아옴

 

억지스럽지만, 아래와 같은 코드가 있다고 가정해 보겠습니다.

참고로 mutableStateFlow에서는 반드시 초기화 값을 넣어주어야 합니다.

 

private val _refreshTrigger = MutableStateFlow(true)
private val refreshTrigger = _refreshTrigger.asStateFlow()

 

refreshTrigger에서 flow 데이터가 흘러나오면 네트워크를 호출하도록 되어 있습니다.

 

var networkResult = refreshTrigger
    .flatMapLatest { 
        repository.fetchNetworkResults()
    }

 

 

유저가 버튼을 클릭하면 viewModel에서 아래와 같은 코드가 호출되도록 하였다고 가정해 보겠습니다.

 

viewModelScope.launch {
    _refreshTrigger.emit(true)
}

 

이 경우, 새로운 네트워크 호출이 이루어질까요?

정답은 아닙니다 입니다.

왜냐하면, 위의 안드로이드 공식문서의 설명처럼,

value 값의 변화가 없는 상태이므로, 값을 업데이트하기위해서 flow 데이터를 흘려보내주지 않기 때문입니다.

 

그렇다고, 클릭할 때마다, 의미없이 한번은 true, 한번은 false를 토글해서 보내는 것은,

억지로 StateFlow를 사용해야 하기는 하지만,

매번 기존값을 확인해야 하는 번거로움이 발생하게 됩니다.

 

애초에, StateFlow는 이런 이벤트를 핸들링하거나 이벤트에 트리거되도록 설계된 API가 아니기 때문입니다.

 

2-2. 항상 최신 값을 받게 되는 API

StateFlow는 가장 최신의 업데이트(변경이 있는) 된 값을 흘려보내주는 API입니다.

만약 아래와 같이 A, B, C 값이 차례로 흘러나오고 있을 때,

언제 Collecting 하는 냐에 따라서 받는 값이 달라집니다.

2번 시점에 Collect하기 시작하면 받는 값은 B 가 됩니다.

Collect 하기 이전에 방출된 값이라도 최신의 값을 전달해 주는 것 입니다.

 

언제 Collect 하던지 가장 최신의 값을 전달받을 수 있는데요.

이러한 개념은 StateFlow의 존재이유이기도 한데요.

 

  ________            ________            ________
 | Value A | ------> | Value B | ------> | Value C | ------>
  --------             --------            --------
               (1)                  (2)                 (3)

 

 

2-3. 한번에 하나의 값만을 가짐

일반적인 flow와는 다르게, 여러개의 값을 가질 수 없구요.

가장 최신의 하나의 값만을 가질 수 있는 API 입니다.

물론, 그렇다고 list나 Pair 같은 데이터타입을 못 쓰는 것은 아닙니다.

 

3. SharedFlow

SharedFlow는 여러 콜렉터들에게 flow데이터를 전달해 줄 수 있는 Flow API 인데요.

안드로이드 문서의 예시로 든것 중 하나가,

앱 전체에 tick을 보내서, 정기적으로 앱의 데이터들이 refresh되게 할 수 있다고 나와있습니다.

 

 

그렇다고 해서, StateFlow에는 한개의 collector만 붙을 수 있는 것은 아닙니다.

마치, 이름만 들으면 여러곳에서 collect할 때는 SharedFlow 아닐때는 StateFlow로 생각할 수도 있지만,

그것만을 기준으로 둘을 나누어 사용할 수는 없습니다.

 

3-1. 이벤트 핸들링에 더 적합

SharedFlow는 StateFlow보다도 이벤트핸들링에 오히려 더욱 적합합니다.

위의 안드로이드 공식문서에도 나온 것 처럼,

프로그램 전체에 tick을 보내서 값을 리프레쉬 할수도 있구요.

StateFlow처럼, 값이 변하는 경우에만 flow데이터를 보내는 API가 아니기 때문입니다.

 

private val _refreshTrigger = MutableSharedFlow<Unit>()
private val refreshTrigger = _refreshTrigger.asSharedFlow()

 

 

초기화 값을 반드시 넣어주어야 했던, MutableStateFlow 와는 다르게,

이 API에서는 초기화 값을 넣어줄 필요도 없습니다.

 

마찬가지로 아래와 같이 emit을 할 때도 Unit을 넣어주어도 문제없이 동작합니다.

 

viewModelScope.launch {
    _refreshTrigger.emit(Unit)
}

 

위에서 보았던, 제대로 동작하지 않는 refreshTrigger는 SharedFlow를 이용하면,

문제없이 동작하게 됩니다.

 

3-2. Collecting 이 되면 값을 흘려보내주는 API

위에서 StateFlow는 collecting 하는 시점의 최신 값을 흘려보내준다고 하였는데요.

SharedFlow는 조금 다릅니다.

Collecting을 시작하는 시점이후에 방출되는 값들을 받게 됩니다.

아래에서 1번시점에 Collecting을 하게 된다면,

A가 최신값임에도 받지 못하고, B부터 받게 됩니다.

(반면, StateFlow에서는 1번시점에 Collecting하면 A값을 바로 최신값으로 받을 수 있었지요.)

 

  ________            ________            ________
 | Value A | ------> | Value B | ------> | Value C | ------>
  --------             --------            --------
               (1)                  (2)                 (3)

 

 

3-3. 여러개의 값을 한번에 보낼 수 있음

StateFlow가 하나의 single 값만을 보낼 수 있었는데요.

SharedFlow는 여러개의 값을 한번에 보낼 수 있습니다.

일반적인 Flow와 이 부분에서는 동일합니다.

 

3-4. Buffer 나 Replay 같은 옵션을 제공

이 부분은 아래 글에 정리되어 있는데요.

StateFlow와는 다르게, 좀 더 많은 옵션들을 제공해 줍니다.

 

>> SharedFlow 에 대한 총정리 # Buffer Replay tryEmit Kotlin Coroutine

 

4. 비교

마지막으로 간단하게 도표로 둘을 비교해 보도록 하겠습니다.

 

구분 StateFlow SharedFlow
초기화 값 반드시 필요 필요없음
이벤트 핸들링 적합하지 않을 수 있음.
변경되는 최신값만 흘려보내 줌
적합함
하나의 값만 가짐 하나의 값만 보낼 수 있으며,
최신값으로 항상 유지
여러개의 값을 방출할 수 있음
Buffer, Replay 옵션 없음 있음.
방출(emit) 시점 collecting 시작되면,
가장 최신값을 방출해 줌
Collecting이 시작되고 나면,
기존의 최신값은 방출해주지 않고,
이 후 방출되는 값부터 방출해 줌.
다만, buffer나 replay로 이런 것들을 컨트롤 할 수 있음
멀티 컬렉터 지원 여러 collector 들에서 Collecting 가능 동일(여러 Collector 들이 Collect 가능)
주 용도 State 변경이나 
최신값만 중요한 dataStream 에 적합
이벤트나 DataStream 에 적합

 

이상으로 StateFlow vs SharedFlow 에 대해서 비교해 보았습니다.

728x90

댓글