https://kotlinlang.org logo
Title
d

dave08

03/15/2018, 1:40 PM
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

elizarov

03/15/2018, 1:41 PM
Because you did not suspend the`produce`. See my answer above. You should wait for cancellation inside produce after the callback is set
define:
suspend fun awaitCancel(): Nothing = suspendCancellableCoroutine {}
d

dave08

03/15/2018, 1:41 PM
Oh, thanks!
d

dave08

03/15/2018, 1:52 PM
Now we did this:
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

deviant

03/15/2018, 2:01 PM
i use
delay(Long.MAX_LONG)
for such cases. probably not the best solution though 🙂
e

elizarov

03/15/2018, 2:02 PM
Maybe
delay(Long.MAX_LONG)
overflows or something like that (and does not wait)
d

deviant

03/15/2018, 2:03 PM
hmm. what do you mean by overflows?
e

elizarov

03/15/2018, 2:04 PM
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

deviant

03/15/2018, 2:05 PM
oh, android. i remember that brilliant fix with
/2
🙂
e

elizarov

03/15/2018, 2:05 PM
Overflows as in the following code:
val deadline = curTime + timeout //MAX_LONG !!
// so deadline is negative
whiile (curTime < deadline) wait() // aha!!!
//
d

deviant

03/15/2018, 2:05 PM
now it works as expected
d

dave08

03/15/2018, 2:06 PM
I think it's not waiting with
awaitCancel
... when we did it with delay it worked...?
e

elizarov

03/15/2018, 2:06 PM
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

dave08

03/15/2018, 2:08 PM
Here's the current 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

elizarov

03/15/2018, 2:09 PM
Maybe. Can you reproduce this problem in some self-contained example?
d

dave08

03/15/2018, 2:45 PM
Now I corrected it (I hope), but the first test still hangs...
e

elizarov

03/15/2018, 3:06 PM
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:
val result = async {
        channel.any {
            if (it.action == "hello") {
                channel.cancel(); true
            } else false
        }
    }
    context.send("hello")
    assert(result.await())
d

dave08

03/15/2018, 3:14 PM
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.