Ale
09/07/2020, 11:29 AM@ExperimentalCoroutinesApi
private fun retrieveFromFirestore(porteroId: String): Flow<Portero> = callbackFlow {
val porteroCallback = EventListener<QuerySnapshot> { querySnapshot, e ->
val element = //extract data from snapshot etc.
launch { //save to local sqllite }
offer(element)
}
}
This works well.
However, when I tried to refactor the code a bit, and extract the snapshot manipulation to another method:
@ExperimentalCoroutinesApi
private fun retrieveFromFirestore(porteroId: String): Flow<Portero> = callbackFlow {
val porteroCallback = EventListener<QuerySnapshot> { querySnapshot, e ->
val element = buildData(querySnapshot, e)
offer(element)
}
}
private buildData(querySnapshot: QuerySnapshot?, e: FirebaseFirestoreException?): Element {
//extract data from snapshot etc.
launch { //save to local sqllite } // <--- this doesn't compiles
return element
}
The launch function is no longer available, with the error Unresolved reference.
I can fix it using CoroutineScope(Dispatchers.Default).launch { ... } but why is this happening? How come launch is available only in the calling function but not in the called one?Manuel Vivo
09/07/2020, 11:34 AMsuspend function, and in order to create new coroutines inside a suspend function, you need a scope (e.g. coroutineScope or supervisorScope depending on whether you want a Job or SupervisorJob as a parent)wasyl
09/07/2020, 11:38 AMlaunch is not accessible anymore: launch is an extension function on CoroutineScope. The `callbackFlow`’s parameter (the lambda) is defined as block: suspend ProducerScope<T>.() -> Unit, and ProducerScope implements `CoroutineScope`: interface ProducerScope<in E> : CoroutineScope.
So when calling launch inside callbackFlow lambda you simply have a CoroutineScope in scope. When you extract a function like this, you need to follow what Manuel said: make the extracted function `suspend`able and start a new scope using coroutineScope { } builder.Ale
09/07/2020, 11:42 AM