Kotlin Coroutines - Launching flow
지금까지 비동기 이벤트를 플로우를 통해 표현하는 방법에 대해서 알아보았다.
일반적인 비동기 이벤트 상황을 떠올려보자.
어떠한 이벤트가 발생하였을 때, 해당 이벤트를 처리하기 위해 addEventListener
등을 등록하여 후처리를 하는 것이 일반적일 것이다.
플로우에는 onEach
연산자가 이 역할을 담당한다.
1. onEach
onEach
로 addEventListener
를 대치할수 있다고 언급하였다.
다만 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 | Event: 1 |
이벤트를 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 | Done |
launchIn
종단 연산자를 사용함으로서 플로우의 수집을 별개의 코루틴에서 수행하도록 할 수 있다.
별개의 코루틴이기때문에 별도의 CoroutineScope
를 필요로 하며, 위 예제에서는 runBlocking
을 통해 전달받았다.
또 하나 특기할 점은 코루틴의 구조화된 동시성으로 인해 addEvent
는 있어도 removeEvent
는 필요없다는 점이다.
launchIn
역시 Job
을 반환하므로 이를 통해 코루틴 플로우를 취소하도록 제어해야 한다.