(Kotlin Coroutines) 013. Launching flow

Kotlin Coroutines - Launching flow

지금까지 비동기 이벤트를 플로우를 통해 표현하는 방법에 대해서 알아보았다.

일반적인 비동기 이벤트 상황을 떠올려보자.

어떠한 이벤트가 발생하였을 때, 해당 이벤트를 처리하기 위해 addEventListener 등을 등록하여 후처리를 하는 것이 일반적일 것이다.

플로우에는 onEach 연산자가 이 역할을 담당한다.

1. onEach

onEachaddEventListener를 대치할수 있다고 언급하였다.

다만 onEach는 중간 연산자이기 때문에 collect와 같은 종단 연산자를 호출해야만 플로우가 대기 상태로 이벤트를 기다리게 될 것이다.

이벤트는 언제고 계속해서 발생할 수 있기때문에 onEach를 써야하고,

onEach를 대기시키기 위해 collect를 쓰게되는데 collect는 플로우의 스트림이 끝날때까지 대기하게 된다.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun events(): Flow<Int> = (1..3).asFlow().onEach { delay(100) }

fun main() = runBlocking<Unit> {
    events()
        .onEach { event -> println("Event: $event") }
        .collect()
    println("Done")
}   

출력 결과

1
2
3
4
Event: 1
Event: 2
Event: 3
Done

이벤트를 collect로 받는 이상 다른 플로우(혹은 이벤트)를 처리할 수 없게되는 것이다.

2. launchIn

종단 연산자 collect는 위에서 언급했듯 이벤트 처리를 위해 사용할 수 없다.

코루틴 플로우는 이를 해결하기 위해 launchIn이라는 종단 연산자를 제공한다.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun events(): Flow<Int> = (1..3).asFlow().onEach { delay(100) }

fun main() = runBlocking<Unit> {
    events()
        .onEach { event -> println("Event: $event") }
        // .collect()
        .launchIn(this) // HERE
    println("Done")
}   

출력 결과

1
2
3
4
Done
Event: 1
Event: 2
Event: 3

launchIn 종단 연산자를 사용함으로서 플로우의 수집을 별개의 코루틴에서 수행하도록 할 수 있다.

별개의 코루틴이기때문에 별도의 CoroutineScope를 필요로 하며, 위 예제에서는 runBlocking을 통해 전달받았다.

또 하나 특기할 점은 코루틴의 구조화된 동시성으로 인해 addEvent는 있어도 removeEvent는 필요없다는 점이다.

launchIn 역시 Job을 반환하므로 이를 통해 코루틴 플로우를 취소하도록 제어해야 한다.