Nikola Milovic
08/15/2020, 6:05 PMemit
says it has to be ran from a coroutine body ( I am well aware it is a suspend function)?
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
class FirebaseDataSource (private val firebaseFirestore: FirebaseFirestore) : NetworkDataSource{
fun fetchMenuItems(): Flow<Food> = flow{
firebaseFirestore.collection("menu_items")
.get()
.addOnSuccessListener { documents ->
try {
for (document in documents) {
val doc =...
emit(doc) //error here
}
}
}
}
In every example I've seen online they have it just inside the flow {}
Eg.
fun simple(): Flow<Int> = flow {
for (i in 1..3) {
delay(100)
println("Emitting $i")
emit(i)
}
}
tseisel
08/15/2020, 6:13 PMflow
block has been reached.
Two suggestions here:
1. write an equivalent of get()
that suspends. You can do that using suspendCancellableCoroutine
.
2. Use callbackFlow
.akatkov
08/15/2020, 6:15 PMawait
after the get()
to convert the Task to suspending e.g. val documents = firebaseFirestore.collection("menu_items").get().await()
akatkov
08/15/2020, 6:16 PMsuspendCancellableCoroutine
as mentioned aboveMark Murphy
08/15/2020, 6:27 PMflow
is a coroutine body. However, the OnSuccessListener
lambda expression is not part of that coroutine body. That converts into a separate function on a separate object and lives separate from the Flow
.
callbackFlow()
would allow you to adapt this callback-based API to a `Flow`: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/callback-flow.html
Or, there seem to be some existing Firebase-with-coroutines libraries, such as https://github.com/brotoo25/firestore-coroutines.Michal Harakal
08/16/2020, 5:03 PM