I have a small problem when converting a callback ...
# coroutines
m
I have a small problem when converting a callback to a suspend function. Im trying to wait for a field to be created on a document (firestore) and when the field is created, return the data and continue execution. It works, but since the document listener still is active, Ill get an exception on the next change of the document (alreadyResumedError)
Copy code
suspend fun waitForField(id: String): DocModel? = suspendCancellableCoroutine {
    val listener = db.collection("collection").document(id)
        .addSnapshotListener { snapshot, e ->
            if (snapshot == null) return@addSnapshotListener
            val res = snapshot.toObject(DocModel::class.java)
            if (res?.calculation != null) {
                // here i have to disconnect the listener
                it.resume(res)
            }
        }

    it.invokeOnCancellation {
        listener.remove()
    }
}
d
It would be more appropriate to use
callbackFlow { .... }.first()
for this use case.
Here is a rough sketch of what it might look like.
Copy code
callbackFlow {
val listener = stuff.addListener { snapshot, e ->
  if (snapshot != null) send(snapshot.toObj(...))
}
awaitClose { listener.remove() }
}.first()
Ideally you want to make a
snapshotFlow()
function for documents.
m
Well, I want to wait for a specific field to be created and when it is created, send the data to the waiting coroutine and at the same time stop listen for updates
a callbackflow seems more appropriate for when I want several updates sent “upwards” ?
d
first()
->
first { it?.calculation != null }
then.
A callbackflow is more appropriate for when you have a stream of data coming through a callback, as supposed to a one off callback.
💡 1
m
aha. now I get it. Ill try, thanks
r
You would just need to have a boolean flag to check if you've already resumed