Saiedmomen
08/15/2019, 5:47 PMrunBlocking
block in test gets stuck at collect
call. I think the awaitClose
call suspends the runBlocking
scope but doesn't affect the android code somehow. Can you please tell me if I'm doing it right and how I can write unit tests for it?Saiedmomen
08/15/2019, 5:57 PMcoder82
08/15/2019, 6:13 PMJacques Smuts
08/15/2019, 6:52 PM.collect
gets cancelled, then the awaitClose
block gets called.
However if a CoroutineContext is suspended on a Channel’s .receive()
and gets cancelled, then the invokeOnClose
on that Channel does not get called. You have to manually close the channel. Is that expected behaviour? There’s no automatic propagation of Coroutine cancellation into Channels?coder82
08/15/2019, 7:34 PMYuri
08/15/2019, 11:13 PMprivate val keyChangesObservable: Observable<String>
init {
keyChangesObservable = io.reactivex.Observable.create(ObservableOnSubscribe<String> { emitter ->
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> emitter.onNext(key) }
emitter.setCancellable { prefs.unregisterOnSharedPreferenceChangeListener(listener) }
prefs.registerOnSharedPreferenceChangeListener(listener)
}).share()
}
Dariusz Kuc
08/16/2019, 8:16 PMawaitAll
will throw first encountered exception
Is there a better way than
val results: List<Deferred<Any>> = ... // whatever
results.joinAll()
for (result in results) {
val error = result.getCompletionExceptionOrNull()
if (error != null) {
// handle error
} else {
result.await()
}
}
coder82
08/16/2019, 9:55 PMSaiedmomen
08/17/2019, 5:20 AMaddamsson
08/18/2019, 10:19 AMrunBlocking {
withContext(someContext) {
// ...
}
}
My problem is that these functions will be called from each other which would lead to nested `runBlocking`/`withContext` calls. I tried how this works here:
runBlocking {
println("In runBlocking 0")
println("Current thread: ${Thread.currentThread().name}")
withContext(Dispatchers.Single) {
println("In withContext 0")
println("Current thread: ${Thread.currentThread().name}")
runBlocking {
println("In runBlocking 1")
println("Current thread: ${Thread.currentThread().name}")
withContext(Dispatchers.Single) {
println("In withContext 1")
println("Current thread: ${Thread.currentThread().name}")
}
}
}
}
but the problem is that here In withContext 1
never gets printed. What is the best practice when one needs to nest these calls but has to keep the API accessible from Java?Amanjeet Singh
08/19/2019, 8:35 AMval a = async { doSomeA( ) }
val b = async { doSomeB( ) }
zipper( a.await( ), b.await( ) )
carbaj0
08/19/2019, 8:49 AMtailrec suspend fun call() : SomeObject =
if (!isAttempting)
startRetrievingCall()
else
call()
ursus
08/19/2019, 3:08 PMSam Garfinkel
08/19/2019, 8:41 PMzak.taccardi
08/20/2019, 1:18 AMExecutor
as a parameter. How can I create an Executor
that is backed by Dispatchers.Default
? There is no CoroutineDispatcher.asExecutor()
function unfortunatelymyanmarking
08/20/2019, 9:42 AMcoder82
08/20/2019, 11:59 AMdamian
08/20/2019, 3:44 PMnapperley
08/20/2019, 10:34 PMDavid Glasser
08/21/2019, 4:05 AMAssertions.assertThrows
doesn't work if the block calls a suspend function, because the (Java) function isn't inline
. What do people do here? Write their own version?Allan Wang
08/21/2019, 8:01 AMcoder82
08/21/2019, 12:26 PMahulyk
08/21/2019, 2:19 PMSergio Crespo Toubes
08/21/2019, 4:27 PMLuis Munoz
08/21/2019, 4:36 PMDavid Glasser
08/21/2019, 5:22 PM.flowOn(<http://Dispatchers.IO|Dispatchers.IO>)
for this — that's the opposite of what I want as it affects where the emission happens. Do I just want to do launch with context inside collect?
someFlow().map { ... }.filter{ ... }.collect { x ->
launch(<http://Dispatchers.IO|Dispatchers.IO>) { doSomethingBlockingWith(x) }
}
Like this?David Glasser
08/21/2019, 5:56 PMsupervisorScope
. (Lots of questions this morning!)
JobSupport.childCancelled
claims that it has this invariant:
* Invariant: never returns `false` for instances of [CancellationException], otherwise such exception
* may leak to the [CoroutineExceptionHandler].
but SupervisorCoroutine's override always returns false, even for CancellationException? Mostly I'm trying to understand if with CoroutineExceptionHandler/supervisorScope I need my handler to ignore CancellationException. (I think the answer appears to be no from my tests — the CEH never gets the CancellationException, right?)myanmarking
08/22/2019, 1:07 PMcoder82
08/22/2019, 2:39 PMRobert Menke
08/22/2019, 2:42 PMChannel
, launch a coroutine in CoroutineContext
A to send some data through the channel, and then launch a coroutine in CoroutineContext
B in order to receive that data?
I threw together a basic example and it looks like you must send/receive to/from a channel in the same CoroutineContext
. If so, why is this the case?Robert Menke
08/22/2019, 2:42 PMChannel
, launch a coroutine in CoroutineContext
A to send some data through the channel, and then launch a coroutine in CoroutineContext
B in order to receive that data?
I threw together a basic example and it looks like you must send/receive to/from a channel in the same CoroutineContext
. If so, why is this the case?kingsley
08/22/2019, 2:49 PMAm I able toYes
it looks like you must send/receive to/from a channel in the sameNo. It doesn’t have to be the same coroutine context. You can go through the documentation on channels. It shows several examples of this https://kotlinlang.org/docs/reference/coroutines/channels.htmlCoroutineContext
Robert Menke
08/22/2019, 3:16 PMfun main() {
runBlocking {
produce()
consume()
}
}
val channel = Channel<String>()
suspend fun produce() {
coroutineScope {
launch {
println("Producing")
channel.send("Hello world")
println("Done producing")
}
}
}
suspend fun consume() {
coroutineScope {
launch {
println("Consuming")
val value = channel.receive()
println(value)
}
}
}
My understanding is that the coroutineScope
builder creates a new scope that inherits the context of its parent, which in this case is blocking.
I don’t understand why channel.send
is blocks the thread in this case though. Done producing
is never printed.fun main() {
runBlocking {
produce()
consume()
}
}
val channel = Channel<String>()
fun CoroutineScope.produce() {
launch {
println("Producing")
channel.send("Hello world")
println("Done producing")
}
}
fun CoroutineScope.consume() {
launch {
println("Consuming")
val value = channel.receive()
println(value)
}
}
fun main() {
runBlocking {
produce()
consume()
}
}
val channel = Channel<String>()
suspend fun produce() {
coroutineScope {
launch {
println("Producing")
channel.send("Hello world")
println("Done producing")
}
}
}
suspend fun consume() {
coroutineScope {
launch {
println("Consuming")
val value = channel.receive()
println(value)
}
}
}
but this does
fun main() {
runBlocking {
produce()
consume()
}
}
val channel = Channel<String>()
fun CoroutineScope.produce() {
launch {
println("Producing")
channel.send("Hello world")
println("Done producing")
}
}
fun CoroutineScope.consume() {
launch {
println("Consuming")
val value = channel.receive()
println(value)
}
}
??streetsofboston
08/22/2019, 3:44 PMcoroutineScope { ... }
only resumes/returns after all its child coroutines have finished.
In your example, the courtineScope
calls `launch`creating a child-coroutine that never finishes.
It never finishes, because this child-coroutine calls channeld.send
on a RENDEZVOUS channel. the send
call will never resume/return.channel.send
never resumes because the channel.receive
is never called.channel.receive
is never called because the consume
function is never called. This is because produce
never resumes/returns in your first code-sample.kingsley
08/22/2019, 3:45 PMproduce
and consume
are 2 suspending methods, and they both follow structured concurrency which is good.
But this means they will execute sequencially. consume
will only get called after produce
has completed. But this will never happen because produce will get suspended waiting for a consumer that will never come
The second example is indeed the right way to go about this, since each method is executed concurrently, so produce and consume are able to communicate with each other
If you really want 1 to work though, you could set a buffer value for the channel, but that doesn’t really scale if you want implement a proper channel based setupRobert Menke
08/22/2019, 3:47 PMBecausebeing the key reason 👍only resumes/returns after all its child coroutines have finished.coroutineScope { ... }
bdawg.io
08/23/2019, 3:46 AMcoroutineScope
to best understand how you would pick one over the other
https://youtu.be/Mj5P47F6nJg▾