설명에 앞서
-> StateFlow, SharedFlow는 Hot stream입니다.
State flow
private val _stateFlow = MutableStateFlow(99)
val stateFlow = _stateFlow
// state flow에 데이터 전달
suspend fun startSendDataToStateFlow() {
repeat(10) {
_stateFlow.value = it
//_stateFlow.emit(it) 으로도 사용 가능
delay(500)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
...
MainScope().launch {
testViewModel.stateFlow.collect {
Log.i(TAG, "stateFlow #1: $it - ${Thread.currentThread().name}")
}
Log.d(TAG,"State Collect End #1 - ${Thread.currentThread().name}")
}
// emit 시작
MainScope().launch { testViewModel.startSendDataToStateFlow() }
}
-> collect 후 값을 emit해주고 있으므로 collect 시점에서는 아직 방출된 데이터가 없기 때문에 기본값을 받아갑니다. 따라서 99부터 수신되며 그 이후 방출된 0~9의 데이터가 collect를 통해 수신되게 됩니다.
(만약 emit이 먼저 호출된 이후 collect 된다면 초기값이 99가 아닌 이미 stateFlow에 담겨져있는 0부터 전달받게 됩니다.)
Shared Flow
private val _sharedFlow = MutableSharedFlow<Int>(
replay = 0,
extraBufferCapacity = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)
val sharedFlow = _sharedFlow
replay : collect시 전달받을 이전 데이터의 갯수를 지정합니다.
ex) 0->1->2->3-> collect 시작->4->5->6->7->8->9
extraBufferCapacity : buffer 개수 설정을 정합니다. flow의 emit이 빠르고 collect가 느릴 때 지정된 갯수만큼 buffer에 저장되며 지정된 갯수가 넘어가면 onBufferOverflow에 설정된 정책에 따라 동작합니다.
onBufferOverflow : Buffer가 다 찼을 때의 동작을 정의합니다.
private val _sharedFlow = MutableSharedFlow<Int>(
replay = 0,
extraBufferCapacity = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)
val sharedFlow = _sharedFlow
// SharedFlow에 데이터 전달
suspend fun startSendDataToSharedFlow() {
repeat(10) {
_sharedFlow.emit(it)
delay(500)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
...
MainScope().launch { testViewModel.startSendDataToSharedFlow() }
MainScope().launch {
testViewModel.sharedFlow.collect {
Log.i(TAG, "sharedFlow #1: $it - ${Thread.currentThread().name}")
}
Log.d(TAG,"Shared Collect End #1 - ${Thread.currentThread().name}")
}
...
-> emit 이후 collect를 수행하므로 collect 이후 수신되는 값인 1부터 수신받게 됩니다.
SharedFlow vs StateFlow
// StateFlow 생성
private val _stateFlow = MutableStateFlow(99)
val stateFlow = _stateFlow
// SharedFlow 생성
private val _sharedFlow = MutableSharedFlow<Int>(
replay = 0,
extraBufferCapacity = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)
val sharedFlow = _sharedFlow
// 양쪽 flow에 "100" 을 다섯번 반복 전송
suspend fun repeatSameDataToEachFlow() {
repeat(5) {
Log.d(TAG, "sendData #$it")
_sharedFlow.emit(100)
_stateFlow.value = 100
delay(500)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
...
// sharedFlow collect
MainScope().launch {
testViewModel.sharedFlow.collect {
Log.i(TAG, "sharedFlow: $it")
}
}
// stateFlow collect
MainScope().launch {
testViewModel.stateFlow.collect {
Log.i(TAG, "stateFlow: $it")
}
}
// 양쪽 flow에 emit 시작
MainScope().launch {
testViewModel.repeatSameDataToEachFlow()
}
}
-> sharedFlow, stateFlow 양쪽에 100이란 값을 5번 반복해서 전송합니다.
결과는
즉 동일한 값이 입력되면 stateFlow의 경우 내부적으로 skip하여 collect 자체가 호출되지 않습니다.