https://kotlinlang.org logo
#coroutines
Title
# coroutines
p

Paul Woitaschek

04/29/2019, 3:17 PM
I want to create a suspending function that calls
startActivityForResult
and it suspends until
onActivityResult
is called. Is using a Channel the right way to do that?
Copy code
kotlin
class MyActivty : Activity(){

  private val channel = Channel<Uri>()

  override fun onActivityResult(data: Intent){
    val uri = data.data
    channel.offer(uri)
  }


  suspend fun soSthWithStartActivtyForResult() : Uri {
     startActivityForResult(intent, 42)
     return channel.receive()
  }
}
s

streetsofboston

04/29/2019, 3:18 PM
I think I’d use
suspendCancellableCoroutine
for this.
p

Paul Woitaschek

04/29/2019, 3:19 PM
And keep a list of continuations instead of the channel?
s

streetsofboston

04/29/2019, 3:20 PM
Yep. But you can ‘resume’ only once, though. Launching the activity and waiting for it again would require a new continuation.
p

Paul Woitaschek

04/29/2019, 3:28 PM
Btw, there is
suspendCoroutine
- there is nothing cancellable when calling
startActivityForResult
.
s

streetsofboston

04/29/2019, 3:29 PM
When your Activity goes away, you may want to cancel it.
If not,
suspendCoroutine
is good enough.
You’d need some response for
soSthWithStartActivtyForResult
when the launching activity is cancelled, i.e. onActivityResult is never called.
Something like this?
Copy code
class MyActivity : Activity(), CoroutineScope by MainScope() {
    private var launchContinuation: CancellableContinuation<Uri>? = null

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        launchContinuation?.resume(data!!.data)
    }

    suspend fun soSthWithStartActivityForResult() : Uri = suspendCancellableCoroutine {
        launchContinuation = it
        startActivityForResult(intent, 42)
    }

    override fun onDestroy() {
        super.onDestroy()
        
        launchContinuation?.cancel()
    }
}
l

louiscad

04/29/2019, 5:44 PM
This will not survive lifecycle destroy unfortunately
h

hannesstruss

04/30/2019, 8:57 AM
Yeah, trying to coerce Android's request/response APIs like runtime permissions or activity results into fluent callback APIs or Rx has been problematic for me in the past. If your process dies and is restored, your listener isn't registered anymore and your result is lost. It's less elegant but safer to treat activity/permission results as a hot "channel" that can emit anytime.
l

louiscad

04/30/2019, 9:09 AM
Runtime permissions are different, because they are idempotent: you can check if it's currently granted, and requesting again will produce a success. In fact, I released a library for that yesteray night: https://github.com/LouisCAD/Splitties/tree/master/modules/permissions
d

dekans

04/30/2019, 9:22 AM
I did something related for runtime permission: https://medium.com/@geoffrey.metais/android-runtime-permissions-in-one-suspending-function-b2774bb22e4b With a headless retainInstance fragment, you can survive rotation
👍 1
4 Views