Could registerForActivityResult be used in a coroutine?

Viewed 729

The problem with this as I see it is that you have to guarantee that registerForActivityResult() is called before your own activity's OnCreate() completes. OnCreate() is obviously not a suspending function, so I can't wrap registerForActivityResult() and ActivityResultLauncher.launch() in a suspendCoroutine{} to wait for the callback, as I can't launch the suspendCoroutine from OnCreate and wait for it to finish before letting OnCreate complete...

...which I did think I might be able to do using runBlocking{}, but I have found that invoking runBlocking inside OnCreate causes the app to hang forever without ever running the code inside the runBlocking{} block.

So my question is whether runBlocking{} is the correct answer but I am using it wrong, or whether there is some other way to use registerForActivityResult() in a coroutine, or whether it is simply not possible at all.

1 Answers

You can do something like this. Please refer to the implementation below.

class RequestPermission(activity: ComponentActivity) {
    private var requestPermissionContinuation: CancellableContinuation<Boolean>? = null
    @SuppressLint("MissingPermission")
    private val requestFineLocationPermissionLauncher =
        activity.registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
            requestPermissionContinuation?.resumeWith(Result.success(isGranted))
        }

    suspend operator fun invoke(permission: String) = suspendCancellableCoroutine<Boolean> { continuation ->
        requestPermissionContinuation = continuation
        requestFineLocationPermissionLauncher.launch(permission)
        continuation.invokeOnCancellation {
            requestPermissionContinuation = null
        }
    }
}

Make sure you initialize this class before onStart of the activity. registerForActivityResult API should be called before onStart of the activity. Refer to the sample below

class SampleActivity : AppCompatActivity()  {
    val requestPermission: RequestPermission = RequestPermission(this)

    override fun onResume() {
        super.onResume()
        lifecycleScope.launch {
            val isGranted = requestPermission(Manifest.permission.ACCESS_FINE_LOCATION)
            //Do your actions here
        }

    }
}
Related