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