Skip to content

Android Runtime Permission API — Complete Guide

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about Android Runtime Permission API. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

The Problem

You're using the deprecated requestPermissions() and onRequestPermissionsResult() approach, and your code is verbose and error-prone.

Wrong Approach ❌

// Old deprecated approach
requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_CODE)

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
    if (requestCode == REQUEST_CODE && grantResults.isNotEmpty() && grantResults[0] == GRANTED) {
        getLocation()
    }
}

Output: Deprecated code, manual request code handling, easy to mis-match.

Right Approach ✅

class MainActivity : AppCompatActivity() {
    // Single permission launcher
    private val cameraLauncher = registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { isGranted ->
        if (isGranted) {
            openCamera()
        } else {
            showDeniedMessage()
        }
    }

    // Multiple permissions launcher
    private val permissionsLauncher = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions ->
        val allGranted = permissions.values.all { it }
        if (allGranted) {
            startFeature()
        } else {
            permissions.entries.forEach { (permission, granted) ->
                if (!granted && !shouldShowRequestPermissionRationale(permission)) {
                    // "Never ask again" was checked
                    showSettingsDialog()
                }
            }
        }
    }

    // In Compose
    @Composable
    fun PermissionAwareCamera() {
        val permissionState = rememberPermissionState(Manifest.permission.CAMERA)

        Button(onClick = { permissionState.launchPermissionRequest() }) {
            Text(if (permissionState.status.isGranted) "Camera Ready" else "Request Camera")
        }
    }

    private fun requestPermissions() {
        permissionsLauncher.launch(
            arrayOf(
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.CAMERA
            )
        )
    }
}

Output: Clean, modern permission API with no request codes.

Prevention

  • Use registerForActivityResult with RequestPermission/RequestMultiplePermissions.
  • Use Accompanist rememberPermissionState in Compose.
  • Check shouldShowRequestPermissionRationale after denial in the result callback.
  • Request only permissions your app currently needs.

Common Mistakes with permission runtime

  1. Using foldl instead of foldl' causing stack overflow on large lists
  2. Forgetting deriving (Show, Eq) on custom data types needed for debugging
  3. Placing the wildcard pattern first in case expressions, making all subsequent patterns unreachable

These mistakes appear frequently in real-world Android code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

### How do I request permissions from a Fragment?

Use registerForActivityResult() on the Fragment directly. The contract handles Activity/Fragment lifecycle automatically.

### What is the difference between RequestPermission and RequestMultiplePermissions?

RequestPermission handles one permission at a time. RequestMultiplePermissions handles multiple permissions and returns a Map<String, Boolean>.

### Can I request permissions from a non-UI component?

No. registerForActivityResult() requires a ComponentActivity or Fragment. Use a delegate pattern or pass the result to your ViewModel.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro