Android
Fragment
Activity
onRequestPermissionsResult
Permissions Handling

onRequestPermissionsResult not being called in fragment if defined in both fragment and activity

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

This problem usually appears in older Android permission code: a fragment requests a runtime permission, but the callback never seems to arrive in the fragment. In practice, the callback is often intercepted or disrupted by activity-level handling, or the app is using an outdated pattern that is easy to miswire. The safest answer today is to move permission requests into the fragment with the Activity Result API.

Why the Fragment Callback Can Be Missed

In legacy code, permissions are requested with requestPermissions and handled in onRequestPermissionsResult. That works, but only if the request originates from the right component and the callback chain is preserved.

Common failure modes are:

  • the activity requests the permission instead of the fragment
  • the activity overrides onRequestPermissionsResult and does not call super
  • the fragment is nested and the wrong fragment manager path is involved
  • request logic lives partly in the fragment and partly in the activity

If the fragment started the request, the fragment should own the response handling too.

Legacy Pattern That Often Breaks

This pattern is fragile because the activity becomes a routing layer:

kotlin
1class HostActivity : AppCompatActivity() {
2    override fun onRequestPermissionsResult(
3        requestCode: Int,
4        permissions: Array<out String>,
5        grantResults: IntArray
6    ) {
7        // If you override this and forget super, fragments may not receive the result.
8        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
9    }
10}
kotlin
1class CameraFragment : Fragment() {
2    fun requestCameraPermission() {
3        requestPermissions(arrayOf(android.Manifest.permission.CAMERA), 1001)
4    }
5
6    override fun onRequestPermissionsResult(
7        requestCode: Int,
8        permissions: Array<out String>,
9        grantResults: IntArray
10    ) {
11        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
12
13        if (requestCode == 1001 && grantResults.isNotEmpty()) {
14            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
15                openCamera()
16            }
17        }
18    }
19
20    private fun openCamera() {
21        println("Camera permission granted")
22    }
23}

If the activity callback exists, always call super.onRequestPermissionsResult(...). Without that call, the framework may not dispatch the result back to the fragment.

The Modern Fix: Use registerForActivityResult

The recommended pattern is to register a permission launcher inside the fragment. That removes request-code bookkeeping and avoids most callback forwarding problems.

kotlin
1class CameraFragment : Fragment() {
2
3    private val cameraPermissionLauncher =
4        registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
5            if (granted) {
6                openCamera()
7            } else {
8                showPermissionDeniedMessage()
9            }
10        }
11
12    fun requestCameraPermission() {
13        cameraPermissionLauncher.launch(android.Manifest.permission.CAMERA)
14    }
15
16    private fun openCamera() {
17        println("Camera permission granted")
18    }
19
20    private fun showPermissionDeniedMessage() {
21        println("Camera permission denied")
22    }
23}

This keeps the request and the result handler in the same place, which is exactly what fragments need.

If You Must Keep Legacy Code

Some codebases cannot migrate immediately. In that case, apply these rules:

  1. Call requestPermissions from the fragment, not from the activity, if the fragment owns the feature.
  2. If the activity overrides onRequestPermissionsResult, call super.
  3. Keep request codes unique and local to the component that owns them.
  4. Avoid splitting permission decisions between fragment and activity.

Also verify which fragment class you are using. Mixing old framework fragments and AndroidX fragments has caused many callback issues in older projects.

Request Rationale and Retry Flow

Permission handling is not just about the callback firing. A complete flow should:

  • check whether permission is already granted
  • show rationale when appropriate
  • request only when the user triggers a feature that needs it
  • degrade gracefully if the user denies the request

A minimal check before launching the request:

kotlin
1fun ensureCameraPermission(context: Context) {
2    val granted = ContextCompat.checkSelfPermission(
3        context,
4        android.Manifest.permission.CAMERA
5    ) == PackageManager.PERMISSION_GRANTED
6
7    if (granted) {
8        openCamera()
9    } else {
10        cameraPermissionLauncher.launch(android.Manifest.permission.CAMERA)
11    }
12}

That keeps the control flow predictable and avoids unnecessary permission prompts.

Common Pitfalls

  • Calling ActivityCompat.requestPermissions from the activity for a feature that belongs to a fragment.
  • Overriding the activity callback and forgetting super.onRequestPermissionsResult.
  • Keeping old permission code while also partially migrating to Activity Result APIs.
  • Using nested fragments but assuming the top-level activity will route everything correctly.
  • Requesting permission too early in lifecycle methods instead of in response to a user action.

Summary

  • Fragment permission callbacks often fail because legacy request flow is split between activity and fragment.
  • If you still use onRequestPermissionsResult, make sure the fragment starts the request and the activity calls super.
  • The recommended modern solution is registerForActivityResult inside the fragment.
  • Keep permission ownership local to the UI component that needs the permission.
  • Treat the full user flow, not just the callback method, as part of the implementation.

Course illustration
Course illustration

All Rights Reserved.