안녕하세요.
오늘은 Jetpack Library 중 하나인 Flow의 종류에 대해 알아보겠습니다.
Cold Flow
이전 포스팅에서 봐왔던 Flow 기본 형식은 Cold Flow 입니다.
Cold Flow의 특징은 다음과 같습니다.
특징 - 1
- Collector가 있을 때만 data를 emit 함
아래 코드의 출력을 보면 collect()가 있을 때
producer가 data를 stream에 넣기 시작합니다.
fun testColdFlow() = flow {
println("cold flow is open")
for (i in 1..4) {
delay(100)
emit(i)
}
println("cold flow is closed\n")
}
fun main() = runBlocking {
val startTime = System.currentTimeMillis()
testColdFlow().collect {
println("1st -> ${it} after ${System.currentTimeMillis() - startTime}")
}
}
특징 - 2
- Collector가 수행할 때 다른 Collector가 끝날 때 까지 기다림
첫 번째 Collector가 끝나고 나서,
두 번째 Collector가 수행됩니다.
fun testColdFlow() = flow {
println("cold flow is open")
for (i in 1..4) {
delay(100)
emit(i)
}
println("cold flow is closed\n")
}
fun main() = runBlocking {
val startTime = System.currentTimeMillis()
testColdFlow().collect {
println("1st -> ${it} after ${System.currentTimeMillis() - startTime}")
}
testColdFlow().collect() {
println("2nd -> ${it} after ${System.currentTimeMillis() - startTime}")
}
}
특징 - 3
- stream에 data를 저장하지 못 함
저장을 못하기 때문에 하나의 stream이 multiple collectors를 가질 수 없습니다.
=> stream과 collector는 사실상 1:1 관계
Hot Flow
Cold Flow와 다른 Hot Flow는 아래와 같은 특징이 있습니다.
- Collector가 없을 때도 data를 emit 함
- stream에 data를 저장할 수 있음
- multiple collectors를 가질 수 있음
Hot Flow의 대표적인 예시가 State Flow와 Shared Flow 두 가지 있습니다.
아래 예시를 통해 Hot Flow에 대해 더 알아보겠습니다.
State Flow
- 단일 데이터의 상태를 표현함
- 데이터의 변경 사항을 실시간으로 알림
아래 코드를 보면 StateFlow의 상태가 바뀔 때 마다 collect 돼서 출력되는 것을 볼 수 있습니다.
그리고 StateFlow는 가장 최신의 값 하나만을 저장합니다.
fun main(): Unit = runBlocking {
val currentTime = System.currentTimeMillis()
val stateFlow = MutableStateFlow(0)
val job = launch {
stateFlow.collect {
println("current state : ${it} after ${System.currentTimeMillis() - currentTime}")
}
}
delay(1000)
stateFlow.value = 1
delay(1000)
stateFlow.value = 2
delay(1000)
stateFlow.value = 3
delay(1000)
println("hi")
delay(1000)
job.cancel()
}
stateFlow의 value가 바뀔 때마다 collect가 호출됩니다.
1 : N의 관계
Hot Flow는 stream과 collectors가 1 : N 관계가 가능하다고 했습니다.
아래 예시는 하나의 stateFlow에 3명의 구독자가 있습니다.
stateFlow의 상태가 바뀔 때 마다 3명의 구독자가 알아차리고 연산을 시작합니다.
fun main(): Unit = runBlocking {
val currentTime = System.currentTimeMillis()
val stateFlow = MutableStateFlow(0)
val job1 = launch {
stateFlow.collect {
println("job1 : ${it} after ${System.currentTimeMillis() - currentTime}")
}
}
val job2 = launch {
stateFlow.collect {
println("job2 : ${it} after ${System.currentTimeMillis() - currentTime}")
}
}
val job3 = launch {
stateFlow.collect {
println("job3 : ${it} after ${System.currentTimeMillis() - currentTime}")
}
}
delay(1000)
stateFlow.value = 1
delay(1000)
stateFlow.value = 2
delay(1000)
stateFlow.value = 3
delay(1000)
println("hi")
delay(1000)
job1.cancel()
job2.cancel()
job3.cancel()
}
값이 바뀔 때 마다 3개의 collect가 실행되는 것을 볼 수 있습니다.
LiveData와 차이점?
StateFlow와 LiveData는 비슷한 점이 있습니다.
- 둘 다 관찰 가능한 데이터 홀더 클래스
하지만 이런 차이점이 존재합니다.
StateFlow | LiveData | |
초기 상태 | 초기 상태를 생성자에게 전달해야 함 | 그렇지 않음 |
Life Cycle | - view의 life cycle에 맞춰 실행하지 않음 - 메모리 누수가 발생할 수 있기에 Lifecycle.repeatOnLifecycle 블록에서 써야 취소가 됨 |
- view의 life cycle에 맞춰 실행함 - 뷰가 STOPPED 상태가 되면 자동으로 등록 취소함 |
Shared Flow
- StateFlow의 일반화 버전
- Flow -> (상속) -> ShareFlow -> (상속) -> StateFlow
- 단일 값이 아닌, 원하는 개수의 데이터를 저장함
- 다중 구독자 간에 데이터를 공유하고 처리할 때 사용됨
- Buffer 처럼 사용할 수 있음
안드로이드 공식 문서에서 가져온 코드입니다.
(https://developer.android.com/kotlin/flow/stateflow-and-sharedflow?hl=ko)
앱 전체에 tick을 보내서, 정기적으로 앱의 view 들이 refresh될 수 있도록 하는 예제 코드입니다.
class TickHandler(
private val externalScope: CoroutineScope,
private val tickIntervalMs: Long = 5000
) {
// Backing property to avoid flow emissions from other classes
private val _tickFlow = MutableSharedFlow<Unit>(replay = 0)
val tickFlow: SharedFlow<Event<String>> = _tickFlow
init {
externalScope.launch {
while(true) {
_tickFlow.emit(Unit)
delay(tickIntervalMs)
}
}
}
}
class NewsRepository(
...,
private val tickHandler: TickHandler,
private val externalScope: CoroutineScope
) {
init {
externalScope.launch {
// Listen for tick updates
tickHandler.tickFlow.collect {
refreshLatestNews()
}
}
}
suspend fun refreshLatestNews() { ... }
...
}
여기까지 Flow의 종류에 대해 알아봤습니다.
감사합니다.
참고 자료
https://medium.com/@amitshekhar/cold-flow-vs-hot-flow-ec25da7c198a
https://developer.android.com/kotlin/flow/stateflow-and-sharedflow?hl=ko
'Android Library' 카테고리의 다른 글
[Android Library] Hilt (3) - hilt in MVVM (0) | 2023.10.18 |
---|---|
[Android Library] Hilt (2) - 기본 사용법 (2) | 2023.10.17 |
[Android Library] Hilt (1) - 의존성 주입 (Dependency Injection) (1) | 2023.10.16 |
[Android Library] Flow (2) - 사용하기 (0) | 2023.10.05 |
[Android Library] Flow (1) - Suspend Function의 대안 (2) | 2023.10.05 |