Flow는 데이터의 흐름이다. Flow는 흐름만 발생시킬 뿐 데이터가 저장되지 않는다.
따라서 Flow만을 사용하여 안드로이드의 UIState를 업데이트 하는 것을 불가능 하다.
이를 해결하기 위한 방법이 2가지가 있다.
1번 방법은 비효율적이다.
2번 방법은 효율적이다.
앞선 방법 들은 모두 모일러 플레이트 코드를 발생한다.
안드로이드에서 수집하는 UIState가 한 두가지가 아닐 텐데 모두 구독하기 위해 매번 비슷한 코드의 작성이 강제되는 것은 가독성을 떨어트리게 된다
StateFlow는 데이터 홀더(저장소) 역할과 동시에 Flow의 데이터 스트림 역할까지 맡는다.
- UI단에서 StateFlow를 구독하여 UIState를 업데이트 하면 화면이 재구성될 때 마다 다시 서버로 데이터를 요청할 필요가 없어진다.
- UI는 단순히 StateFlow만을 구독하고 있는 것으로 UI상태를 알 수있다.
리액티브 프로그래밍을 할 때 여러 데이터 흐름을 하나로 합쳐 하나의 데이터 흐름으로 만들어 낸다.
영화 평점앱을 만든다고 할 경우
등을 하나의 StateFlow로 변환하고 UI는 이 StateFlow를 구독하여 항상 최신 데이터를 발행받는다.
이를 위해 Flow를 StateFlow로 변환해 주는 과정이 필요하다.
public fun <T> Flow<T>.stateIn(
scope: CoroutineScope,
started: SharingStarted,
initialValue: T
): StateFlow<T> {
val config = configureSharing(1)
val state = MutableStateFlow(initialValue)
val job = scope.launchSharing(config.context, config.upstream, state, started, initialValue)
return ReadonlyStateFlow(state, job)
}
stateIn은 3가지 변수를 받는다.
이제 Flow를 StateFlow로 변환할 수 있다.
// 1초마다 String값을 반환하는 Flow
val stringFlow: Flow<String> = flow {
for (i in 0..1000) {
emit("integer: $i")
delay(1000)
}
}
val stateFlow = stringFlow.stateIn(
initialValue = "integer 0",
started = SharingStarted.WhileSubscribed(5000),
scope = viewModelScope
)