My problem is it gets closed to early, before this...
# coroutines
d
My problem is it gets closed to early, before this implementation we tried with
any
but the channel was closed before the
offer
in the callback being wrapped...
e
Because you did not suspend the`produce`. See my answer above. You should wait for cancellation inside produce after the callback is set
define:
Copy code
suspend fun awaitCancel(): Nothing = suspendCancellableCoroutine {}
d
Oh, thanks!
d
Now we did this:
Copy code
suspend fun awaitCancel(): Nothing = suspendCancellableCoroutine {}

suspend fun registerBroadcastReceiver(context: Context, intentFilter: IntentFilter): ReceiveChannel<Intent> =
        produce<Intent>(capacity = Channel.UNLIMITED) {
            var broadcastReceiver:BroadcastReceiver? = null
            try {
                broadcastReceiver = object : BroadcastReceiver() {
                    override fun onReceive(context: Context, intent: Intent) {
                        offer(intent)
                    }
                }.also {
                    context.registerReceiver(it, intentFilter)
                    awaitCancel()
                }
            } catch(e: CancellationException) {
                context.unregisterReceiver(broadcastReceiver)
            }
        }
But it's still not suspending, it just continues on with the code...
d
i use
delay(Long.MAX_LONG)
for such cases. probably not the best solution though 🙂
e
Maybe
delay(Long.MAX_LONG)
overflows or something like that (and does not wait)
d
hmm. what do you mean by overflows?
e
There was a bug with that some time in the past. Should have been fixed, but who knows.
Test
delay(Long.MAX_LONG)
separately and if it does not wait report a separate issue about it, please
d
oh, android. i remember that brilliant fix with
/2
🙂
e
Overflows as in the following code:
Copy code
val deadline = curTime + timeout //MAX_LONG !!
// so deadline is negative
whiile (curTime < deadline) wait() // aha!!!
//
d
now it works as expected
d
I think it's not waiting with
awaitCancel
... when we did it with delay it worked...?
e
That is strange.
suspendCancellableCoroutine {}
should wait properly. No chance for it to wakeup, but on cancellation
(no one is there to resume, since we are not even storing its continuation anywhere)
d
Here's the current code:
Copy code
suspend fun registerBroadcastReceiver(context: Context, intentFilter: IntentFilter): ReceiveChannel<Intent> =
        produce<Intent>(capacity = Channel.UNLIMITED) {
            var broadcastReceiver:BroadcastReceiver? = null
            try {
                broadcastReceiver = object : BroadcastReceiver() {
                    override fun onReceive(context: Context, intent: Intent) {
                        offer(intent)
                    }
                }.also {
                    context.registerReceiver(it, intentFilter)
                    awaitCancel()
                }
            } finally {
                context.unregisterReceiver(broadcastReceiver)
            }
        }
Maybe we're doing something wrong?
e
Maybe. Can you reproduce this problem in some self-contained example?
d
Now I corrected it (I hope), but the first test still hangs...
e
I’m looking at at
In your first test you you first suspend in
channel.any
, then you try to send(“hello”) there
You should test it like this:
Copy code
val result = async {
        channel.any {
            if (it.action == "hello") {
                channel.cancel(); true
            } else false
        }
    }
    context.send("hello")
    assert(result.await())
d
That seems to work, thanks!
What's funny is that the test still isn't recreating the exact situation in the app, it's still not suspending there... I guess I'll try working on it in the next few days... if I notice any edge cases, I'll report them back then, thanks anyways.