개요
- 일반적으로 플로우는 콜드 데이터이기 때문에 요청할 때마다 값이 계산됩니다.
- 여러 개의 수신자가 하나의 데이터가 변경되는지 감지하는 경우도 있습니다.
- 이 경우 메일링 리스트와 비슷한 개념인 SharedFlow를 활용할 수 있습니다.
- StateFlow는 감지 가능한 값과 비슷하게 동작합니다.
SharedFlow
- 공유플로우를 통해 메시지를 보내면, 대기하고 있는 모든 코루틴이 수신하게 됩니다.
- 이는 브로드캐스트 채널과 비슷하게 동작합니다.
replay
- 마지막으로 전송한 값들을 저장할 수를 지정합니다.(default:0)
relayCache
resetReplayCache
suspend fun main(): Unit = coroutineScope {
// replay : 마지막으로 전송한 값들을 정한 수만큼 저장, default : 0
// 코루틴이 감지를 시작하면 저장된 값들을 먼저 받음
val mutableSharedFlow = MutableSharedFlow<String>(
replay = 2
)
mutableSharedFlow.emit("message 1")
mutableSharedFlow.emit("message 2")
mutableSharedFlow.emit("message 3")
//replayCache : 값을 저장한 캐시를 나타냄
println(mutableSharedFlow.replayCache)
launch {
mutableSharedFlow.collect{
println("received $it")
}
}
//resetReplayCache : 값을 저장한 캐시를 초기화
mutableSharedFlow.resetReplayCache()
println(mutableSharedFlow.replayCache)
}
MutableSharedFlow
- MutableSharedFlow는 SharedFlow와 FlowCollector를 모두 상속합니다.
- SharedFlow는 Flow를 상속하고 감지하는 목적으로 활용됩니다.
- FlowCollector는 값을 내보내는 목적으로 사용됩니다.
shareIn
- 다양한 클래스가 변화를 감지하는 상황에서 하나의 플로우로 여러 개의 플로우를 만드는 경우 SharedFlow를 활용할 수 있습니다.
- Flow를 SharedFlow로 바꾸는 과정에서 shareIn을 활용할 수 있습니다.
// SharingStarted.Eagerly: 즉시 값을 감지, 전송
// SharingStarted.Lazily: 첫 구독자가 나올 때 감지
// SharingStarted.WhileSubscribed: 첫 구독자가 나올 때 감지
// - 마지막 구독자가 사라지면 플로우 중지
suspend fun main(): Unit = coroutineScope {
val flow = flowOf("A", "B", "C")
.onEach { delay(1000) }
val sharedFlow: SharedFlow<String> = flow.shareIn(
scope = this, // 플로우의 원소를 모으는 코루틴 시작
started = SharingStarted.Eagerly
)
// 총 3회 수집
delay(500)
launch {
sharedFlow.collect {
println("#1 $it")
}
}
// 총 2회 수집
delay(1000)
launch {
sharedFlow.collect {
println("#2 $it")
}
}
// 총 1회 수집
delay(1000)
launch {
sharedFlow.collect {
println("#3 $it")
}
}
}
StateFlow
- 상태플로우는 공유플로우의 개념을 확장시킨 것입니다.
- replay = 1인 공유플로우와 비슷하게 작동합니다.
- value 프로퍼티로 접근 가능한 값 하나를 항상 가지고 있습니다.
suspend fun main(): Unit = coroutineScope {
val state = MutableStateFlow("A")
launch {
state.collect{
println(it)
}
}
delay(100)
// 상태 변화 시 수집하므로, B는 2번 출력
state.value = "B"
launch {
state.collect{
println(it)
}
}
}
- 라이브데이터를 대체하기 위해 지원하며, 안드로이드 의존성이 없다는 특징이 있습니다.
- 코루틴을 지원하며, 초기값을 가지기 때문에 null Safe합니다.
- 데이터가 덮어 씌우쥐기 대문에, 관찰이 늘어날 경우 상태의 중간 변화를 받을 수 없는 경우가 있습니다.
- 모든 이벤트가 필요할 경우 공유 플로우를 활용해야 합니다.
stateIn
- stateIn은 Flow를 StateFlow로 변환합니다.
- shareIn과 마찬가지로 중단 함수이며, StateFlow는 항상 값을 가져야 합니다.
suspend fun main(): Unit = coroutineScope {
val flow = flowOf("a","b","c")
.onEach { delay(1000) }
val stateFlow : StateFlow<String> = flow.stateIn(this)
stateFlow.collect {
println(it)
}
}
- 하나의 데이터 소스에서 값이 변경된 것을 감지하는 경우 주로 활용합니다.