Android M Permissions onRequestPermissionsResult not being called
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
A frequent Android runtime-permission issue is requesting permissions successfully but never receiving onRequestPermissionsResult. This usually happens when the request is sent from one component and the callback is expected in another, or when modern APIs are mixed with legacy callback flows. On Android 6.0 and newer, permissions are asynchronous, so wiring mistakes are easy to miss until users deny or grant at runtime. This guide explains why callbacks disappear, how to fix classic requestPermissions usage, and why ActivityResultContracts is now the safer long-term solution.
Understand the Callback Path
For legacy APIs, the callback returns to the same Activity or Fragment that initiated the request. If a Fragment calls through the Activity incorrectly, the fragment callback may never trigger.
If your Activity is making the request, handle the callback there. If your Fragment is making it, handle it in that fragment. Also ensure request codes are unique and not overwritten.
Prefer ActivityResultContracts for New Code
onRequestPermissionsResult still works, but registerForActivityResult is less error-prone and lifecycle-aware.
This approach avoids manual request codes and reduces callback routing bugs across nested fragments.
Fragment and Activity Integration Rules
Many issues come from mixed ownership. Keep ownership explicit.
If you must centralize permission handling in the activity, expose a callback interface to the fragment. Do not expect both components to automatically receive the same result unless you explicitly forward it.
Also check that you are using AndroidX fragments consistently. Mixing old support fragments and AndroidX fragments can break callback dispatch.
Debugging Checklist
Use logs around request and callback points to confirm control flow:
If callback never logs:
- Verify the request method actually runs.
- Verify component is still attached when callback arrives.
- Confirm no crash or navigation happens before callback.
- Confirm permission is in
AndroidManifest.xml.
Practical Verification Workflow
A reliable way to avoid regressions is to validate the solution in three passes: baseline, controlled change, and repeatability check. First, capture a baseline outcome before you apply fixes. This could be a failing command, a wrong output sample, a stack trace, or a screenshot of current behavior. Second, apply one focused change and rerun exactly the same checks so you can attribute improvements to a specific edit. Third, rerun the checks multiple times or with slightly different inputs to ensure the fix is not accidental or data-specific.
A lightweight template you can adapt for most projects looks like this:
If your environment involves tests, add at least one focused regression test that would fail before the fix and pass after it. This turns a one-time troubleshooting success into a durable maintenance improvement, which is especially important when teams rotate ownership or upgrade dependencies later.
Common Pitfalls
- Calling
ActivityCompat.requestPermissionsin an activity while expecting fragment callback methods to fire. - Using the same request code for multiple permission flows and branching incorrectly.
- Forgetting to call
super.onRequestPermissionsResultin complex fragment hierarchies. - Mixing old support fragments with AndroidX fragments in the same screen.
- Triggering navigation immediately after request, destroying the component before callback execution.
Summary
When onRequestPermissionsResult is not called, the root cause is usually callback ownership or lifecycle mismatch. Keep request and handling in the same component, use unique request identifiers, and migrate new code to ActivityResultContracts. With clear ownership and lifecycle-safe APIs, runtime permission handling becomes predictable and easier to maintain.

