우리는 여러 데이터 흐름(flow)를 하나로 합쳐 하나의 데이터 흐름(flow)를 만들어낸다. 아래에서는 3개의 Flow가 있고 이걸 합쳐서 하나의 Flow를 만든다.
하나로 만들어진 flow는 UI에서 사용되기 위해서 StateFlow로 변환되어야 한다. UI에서는 StateFlow를 구독하여 항상 발행하는 최신의 데이터를 받을 수 있다.
이것이 가능하기 위해서는 Flow -> StateFlow로 변환하는 로직이 필요하다. 또한, StateFlow가 항상 Flow를 구독하고 있으면 메모리 누수가 생기므로 이 StateFlow가 살아있어야 하는 CoroutineScope을 명시할 수 있어야 한다. 우리는 이를 stateIn
함수를 통해 구현할 수 있다.
StateFlow는 Hot Stream이다. 마지막 홀딩하고 있는 데이터를 구독하는 구독자에게 전달할 뿐, 구독자가 구독할 때 발행을 위한 로직을 트리거하지는 않는다.
stateIn 함수를 사용하면 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)
}
아래는 1초마다 String 값을 발행하는 Flow 예제이다.
val stringFlow = flow {
for(i in 0 .. 1000){
emit("integer: $i")
delay(1000)
}
}
이제 위 flow를 stateIn 함수를 이용하여 StateFlow로 변환한다.
SharingStarted.WhileSubscribed(5000)
를 설정한다.val stateFlow = stringFlow.stateIn(
initialValue = "integer 0",
started = SharingStarted.WhileSubscribed(5000),
scope = viewModelScope
)
이렇게 하면 초기 저장값은 "integer 0"이고, collect가 중단되고 5초간만 추가로 발행되고 그 이후에는 발행을 멈추며, ViewModel의 생명주기만큼만 구독받는 행동을 하는 StateFlow가 만들어진다.
이미지는 kotlinworld님의 이미지를 캡쳐하여 사용했습니다.