Android Runtime Permissions With Coroutines

The way to just write single-line for permission more easy?

In this article, you’ll learn how to handle Android runtime permissions from Android Marshmallow using coroutines. This approach will make it easy to handle permissions in Android components with very short code. After reading this article, You’ll no longer need to deal with callback and onResult functions.

The process is quite easy. We need to create a base fragment to handle all the required permission handling with the system. So the core part will be isolated from the rest of the code, and a side benefit is reusability.

Then we have to declare this fragment as an abstract class so that it can be extendable. After that, create another fragment that we extend with the base fragment. Here, we’ll use coroutines to observe the status of the permissions execution in the base and update it to the calling site.

To make state flow a bit less hazy, we have to create a sealed class and include all possible permission callbacks from the system and necessary information like result code.

we are working with four types of results and i think these are alway our usecases:

  • Granted
  • Just Denied
  • Need Rationale
  • Permanently denied.

A sealed class that covers all result types:

BaseController

As part of the plan, we have to create an abstract class with the name BasePermissionControllerFragment and extend it with Fragment.

We have to create an abstract function that can be imported into fragments that extend the base to pass the result quickly

We need to create a function that handles the interaction with the system and use cases like showing a rational message to the user. Then we have to convert the data to our sealed class. Enough with the talk.

What we did is simple: First, we maintained a hashmap of requests that we need to execute with the result code as the key. Then we have to check whether the permissions requested are already granted or if we have to show a rational message. If so, we create a sealed class object with the appropriate type and pass it back.

On the other side, where we have to request access, we have added the result code to the map and invoked the function again. While it was executing for the second time (as the code already exists in the map), the flow enters into the hashmap index block and triggers the actual permissions execution.

After user interactions with the permissions dialog, we’ll receive the result on the onRequestPermissionsResult. We need to create a new instance of the sealed class and pass the data back to the call site.

Finally, we’re done with core permissions handling. Have a look at the base class when we put all the pieces together:

PermissionController

Then we need to create another class with the name PermissionControllerFragment and extend it with BasePermissionControllerFragment. Next, we have to import the abstract function onPermissionResult.

Now, it’s time to write the actual logic using coroutines. Once onPermissionResult is invoked from the base controller, we need to pass permissionStatus back to the call site. To do this with coroutines, we use CompletableDeferred:

“A Deferred that can be completed via public functions complete or cancel.

All functions on this interface [and all interfaces derived from it] are thread-safe and can be safely invoked from concurrent coroutines without external synchronization.” — Kotlin on GitHub

So we have to create an instance of CompletableDeferred with the type permissionStatusand invoke it in the onPermissionResult function. Have a look:

Access

To make permissions handling even more fluid at the call site, we can create a publicly accessible function on the companion object of PermissionControllerFragment and write the boilerplate code.

Call Site

In the call site — either an activity or fragment — we have to invoke requestPermissions from a suspend function or a coroutine scope with Dispatcher.MainAnd once we receive the data, we can handle it using the when keyword and navigate with respect to the state

Other libraries and references:

“A Deferred that can be completed via public functions complete or cancel.

All functions on this interface [and all interfaces derived from it] are thread-safe and can be safely invoked from concurrent coroutines without external synchronization.” — Kotlin on GitHub

So we have to create an instance of CompletableDeferred with the type PermissionResult and invoke it in the onPermissionResult function. Have a look:

Android Developer Passionate about Clean Code, Open Source, Mobile UX, and coffee.