svenjacobs
02/11/2019, 11:48 AMChannel
. However I'm a bit lost here. Here's the simplified pseudo code:
suspend fun Query.onSnapshotAsync(scope: CoroutineScope) =
scope.produce {
addSnapshotListener { snapshot ->
send(snapshot.documents)
}
}
however at send()
it gives me the error suspension functions can be called only within coroutine body
. Usually I wrap legacy callbacks with suspendCoroutine
but in this case this is not possible since the listener fires multiple times but a Continuation can only be resumed once. What is the best practice here?svenjacobs
02/11/2019, 11:52 AMsend()
in scope.launch { send() }
or is there a better solution?Dico
02/11/2019, 12:16 PMoffer
, which returns true if the call was successful.Dico
02/11/2019, 12:17 PMsvenjacobs
02/11/2019, 12:17 PMDico
02/11/2019, 12:18 PMoffer
with a conflated channel, it will always succeed unless the channel is closed or failedsvenjacobs
02/11/2019, 12:19 PMsvenjacobs
02/11/2019, 1:11 PMaddSnapshotListener
adds an asynchronous listener, the produce {}
block ist left immediatly. I think this is the reason why I receive a Channel was closed
exception once offer()
is called.bdawg.io
02/11/2019, 3:25 PMaddSnapshotListener
lambda to throw an exception? Do you want your coroutine scope to handle the exception? I would probably recommend to utilize your coroutine scope to handle the exception and to also not block your snapshot listener with offer. Your onSnapshotAsync
method shouldn’t need to be suspending either. fun Query.onSnapshotAsync(scope: CoroutineScope) = scope.produce(capacity = Channel.CONFLATED) {
addSnapshotListener { snapshot ->
// utilizes your coroutine scope's exception handler
// does not block your snapshot listener thread (potential bug if you move from a conflated channel)
launch { send(snapshot.documents) }
}
}
svenjacobs
02/11/2019, 3:27 PMaddSnapshotListener
is non-blocking?bdawg.io
02/11/2019, 3:32 PM= Channel<List<Snapshot.Document>>(capacity = Channel.CONFLATED).apply {
// attach channel to the lifecycle of the scope (which is based on the Job, if one is attached)
scope.coroutineContext[Job]?.invokeOnCompletion {
close()
}
addSnapshotListener { ... }
}
Dico
02/11/2019, 3:34 PMsvenjacobs
02/11/2019, 3:35 PMsvenjacobs
02/11/2019, 3:36 PMDico
02/11/2019, 3:36 PMsvenjacobs
02/11/2019, 3:39 PMsvenjacobs
02/11/2019, 3:40 PMDico
02/11/2019, 3:42 PMsvenjacobs
02/11/2019, 3:42 PMbdawg.io
02/11/2019, 3:42 PMDico
02/11/2019, 3:43 PMDico
02/11/2019, 3:44 PMproduce
and join on the scope's job at the endsvenjacobs
02/11/2019, 3:44 PMDico
02/11/2019, 3:44 PMDico
02/11/2019, 3:44 PMDico
02/11/2019, 3:45 PMbdawg.io
02/11/2019, 3:50 PMproduce
and try joining, your channel will immediately close (or you could throw an IllegalArgumentException if the scope doesn’t have a Job
attached).
b) If you use Channel
, your channel may leak if the consumer doesn’t close it when it is done (IMO is a bug itself). Choose your poison haha.Dico
02/11/2019, 3:57 PMsvenjacobs
02/12/2019, 6:14 AMChannel
and stores the reference in a property, it should also be responsible for closing the channel, right?bdawg.io
02/12/2019, 2:58 PM