채널은 일종의 파이프라인이다. 채널을 열고 한쪽에서 값을 보내면 다른 쪽에서 수신하는 개념이다.
기본적인 사용법은 간단하다.
val channel = Channel<Int>()
CoroutineScope(Dispatchers.Default).launch {
channel.send(it)
channel.receive()
}
channel.close()
Channel<...>() 함수를 통해 생성할 수 있으며,
데이터를 스트림에 밀어 넣을 땐 send, 스트림에서 받을 땐 receive 를 사용하면 된다.
생성 위치는 상관없지만 send 와 receive 는 suspend 함수이기 때문에 코루틴 내부에서 호출되어야 한다.
채널에 더 이상 아무 데이터도 보내거나 받지 않는다면 채널을 종료시켜야 한다.
close 함수를 통해서 종료시킬 수 있으며,
종료 이후에 send, receive 함수는 ClosedReceiveChannelException 을 발생시킨다.
파이프라인은 채널을 생성하는 패턴으로
하나의 코루틴이 초기 데이터를 생성하고, 소비하는 곳에서 받은 후 새로운 데이터를 생성하는 흐름을 말한다.
유한 또는 무한 개의 값을 만드는 코루틴.
produce<...>{ ... } 함수를 통하여 만들 수 있다.
val numbers = produce<Int> { for (x in 0 .. Int.MAX_VALUE) send(x) }
val numXnum = produce { for (x in numbers) send(x * x) }
사용법은 위와 같으며 결과물로는 0 ~ MAX_VALUE 까지 데이터를 방출하고 그 곱을 방출하는 채널이 만들어진다.
응답값으로 ReceiveChannel 가 반환되며, 해당 채널은 데이터를 추가적으로 보내는 것 ( send ) 은 불가능하고
produce 내부에서 생성된 데이터를 받는 거 ( receive ) 만 가능하다.
다음의 예제 코드를 보자.
val channel = Channel<Int>()
lifecycleScope.launch {
repeat(5){
channel.send(20 + it)
}
}
lifecycleScope.launch {
for(temperature in channel) {
Log.d("TEST", "$temperature")
}
}
이 코드를 실행하면 모두 받고 출력하는 이전 코드와 달리 값을 받을 때마다 출력해준다.
두 코루틴이 채널을 통해서 값을 주고 받을 수 있다. 채널에 send 메서드를 통해 값을 보내면 반대편에서 값을 받을 수 있다. 값을 받기 위해서는 receive 메서드를 받아야하는데 for in 문에서는 자동으로 값을 수신해서 전달해준다. for in은 채널이 닫힐 때까지 값을 받는다. 채널을 닫기 위해서는 명시적으로 close 메서드를 호출할 수 있다.
채널을 만들고 코루틴을 만들어서 값을 전달하는 과정은 반복적인 과정이다. 이 과정을 간단히 만들어주는 빌더 produce가 있다.
val channel = lifecycleScope.produce<Int>{
repeat(5){
channel.send(20 + it)
}
}
lifecycleScope.launch {
for(temperature in channel) {
Log.d("TEST", "$temperature")
}
}