오늘도 더 나은 코드를 작성하였습니까?

Convert callback-based APIs to flows 본문

Coroutine/coroutineFlow

Convert callback-based APIs to flows

hik14 2021. 5. 13. 17:51

callbackFlow는 콜백 기반 API를 흐름으로 변환 할 수있는 flow Builder 입니다

Firebase Firestore Android API는 콜백을 사용합니다.

이러한 API를 flow으로 변환하고 Firestore 데이터베이스 업데이트를 수신하려면 다음 코드를 사용할 수 있습니다.

 

class FirestoreUserEventsDataSource(
    private val firestore: FirebaseFirestore
) {
    // Firestore database 에서 사용자 이벤트 가져오는 함수 
    fun getUserEvents(): Flow<UserEvents> = callbackFlow {

        //  Firestore 참조
        var eventsCollection: CollectionReference? = null
        
        try {
            eventsCollection = FirebaseFirestore.getInstance()
                .collection("collection")
                .document("app")
        } catch (e: Throwable) {
            // 파베가 초기화 안되면 스트림 닫음. 
            // 소비자가 flow collecting을 멈추고 코루틴 재개
            close(e)
        }

        // firestore에 새로운 이벤트가 추가될때 호출될 콜백 등록
        val subscription = eventsCollection?.addSnapshotListener { snapshot, _ ->
            
            if (snapshot == null) { return@addSnapshotListener }
            
            // 이벤트를 flow로 보내고 소비자가 에게 수신된다.
            try {
                offer(snapshot.getEvents())
            } catch (e: Throwable) {
                // 이벤트가 flow로 보내지지 않는다면, 
            }
        }
        
        // awaitClose 내에 콜백은 flow가 닫거나 취소가 될때 실행된다. 
        // 이때 등록된 취소한다. 
        awaitClose { subscription?.remove() }
    }
}

flow Builder 와 달리 callbackFlow는

send 함수를 사용하여 다른 CoroutineContext에서  값을 내보낼수 있고,

offer() 함수를 ​​사용하여 코루틴 외부에 값을 내보낼 수 있도록 할 수 있다.

 

내부적으로 callbackFlow는 개념적으로 a blocking queue와매우 유사한 channel 을 사용합니다.

 

channel은 용량(버퍼링 할 수있는 최대 데이터 수 )으로 구성됩니다.

callbackFlow에서 생성 된 channel의 기본 용량은 64 개 요소입니다.

 

꽉찬 채널에 새 데이터 를 추가하려고 하면,  데이터 를위한 공간이 생길 때까지 

 

send()는 생산자를 일시 중지합니다.

offer()는 데이터를 채널에 추가하지 않고 즉시 false를 리턴합니다.