ChannelFlow와 CallbackFlow

강보훈·2023년 11월 5일
0

Kotlin

목록 보기
1/1

ChannelFlow

channel을 이용해서 코루틴에서 데이터를 주고받기 위한 flow
한 블럭안에서 여러개의 컨텍스트를 사용할 수 있음

channelFlow<Int> {

        launch(Dispatchers.IO){
            flow1.collectLatest {
                print("flow1 $it")
                send(it)
            }
        }

        launch(Dispatchers.Main) {
            flow2.collectLatest {
                print("flow2 $it")
                send(it)
            }
        }

        awaitClose {
            print(">>>> close")
        }
    }

send()를 통해서 채널로 데이터를 보낼 수도 있지만 send() 함수는 suspend가 달려있다.
비동기가아닌 동기형식으로 데이터를 보내고 싶다면

trySendBlocking(it)
	.onFailure {  }
    .onSuccess {  }
    .onClosed {  }
or
trySend(it)

이런 식으로 trySendBlocking, trySend를 통해서도 가능하다
둘의 차이점으로는
trySend()는 버퍼가 꽉 차있는 경우 현재 값을 무시하고 다음 값을 보내려고하며
trySendBlocking()의 경우 버퍼가 꽉 차있는 경우, 버퍼의 자리가 빌때까지 기다린 후 다시 시도한다.

CallbackFlow

위 ChannelFlow가 기반이며 큰 차이는 없다 다만 데이터를 flow밖으로 보내야할 일이 있다면 해당 flow를 사용하면된다.
다만 사용시에 awaitClose를 호출해야 런타임 에러없이 사용이 가능하다.
해당 함수는 close()가 호출될 때 까지 채널을 열어둔 상태로 기다린다.
공식문서에 대한 추가설명으로는

 * Suspends until either 'onCompleted'/'onApiError' from the callback is invoked
 * or flow collector is cancelled (e.g. by 'take(1)' or because a collector's coroutine was cancelled).
 * In both cases, callback will be properly unregistered.

이렇게 설명되어있다.

fun doLogin(api : LoginAPI) = callbackFlow {
        val callback = object : LoginCallback {
            override fun onSuccess(token: String) {
                trySendBlocking(token)
                    .onFailure {

                    }
                    .onSuccess {

                    }
            }

            override fun onFail(error: Exception) {
                cancel()
            }

            override fun onComplete() {
                channel.close()
            }
        }

        api.login(callback)

        awaitClose { api.free(callback) }
    }

아직 실제로 사용해보지 않아 이해도가 높지 않다 실 프로젝트에서 한번 적용시켜봐야 더 정확히 문서를 작성할 수 있을듯 하다.
참고링크

profile
3년차 안드로이드 개발자입니다.

0개의 댓글