I want to create a suspending function that calls ...
# coroutines
p
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
I think I’d use
suspendCancellableCoroutine
for this.
p
And keep a list of continuations instead of the channel?
s
Yep. But you can ‘resume’ only once, though. Launching the activity and waiting for it again would require a new continuation.
p
Btw, there is
suspendCoroutine
- there is nothing cancellable when calling
startActivityForResult
.
s
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
This will not survive lifecycle destroy unfortunately
h
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
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
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