Keywords: Android Permissions System | Nested Fragment | onRequestPermissionsResult | Runtime Permissions | Bit Manipulation Solution
Abstract: This paper provides a comprehensive analysis of the root causes behind the onRequestPermissionsResult() callback not being invoked in Android M's runtime permissions system, with particular focus on the impact of nested Fragment architectures on permission request handling mechanisms. Through detailed code examples and architectural analysis, it reveals the propagation path issues of permission callbacks in complex Fragment hierarchies and presents low-level solutions based on bit manipulation operations. The article also compares the correct usage of permission request methods across different component types (Activity vs. Fragment), offering developers complete technical guidance for resolving similar permission callback failure issues.
Problem Background and Phenomenon Analysis
In the runtime permissions system introduced in Android M (API level 23), developers need to dynamically request dangerous permissions through the requestPermissions method and handle authorization results in the onRequestPermissionsResult callback. However, many developers have encountered situations where the callback method is not triggered as expected.
From the problem description, we can see that the developer correctly followed the permission request flow: initiating the request via ActivityCompat.requestPermissions(getActivity(), permissions, PERMISSIONS_CODE), after which user authorization should trigger the onRequestPermissionsResult callback. However, debugging revealed that this method was never executed, preventing the subsequent SMS sending functionality from automatically triggering and requiring users to manually operate again.
Impact Mechanism of Nested Fragment Architecture
The root cause of the problem lies in complex Fragment nesting architectures. When applications employ multi-layer Fragment inheritance structures, the propagation path of permission callbacks can become abnormal. Specifically, if the project contains nested relationships such as HostedFragment extending CompatFragment, the permission request and callback chain may break at this point.
In the standard Android permission handling mechanism, when a permission request is initiated within a Fragment, the system first delivers the callback to the hosting Activity's onRequestPermissionsResult method, which then distributes the callback to the appropriate Fragment. However, in nested Fragment scenarios, this distribution mechanism may fail to correctly identify the target Fragment, resulting in callback loss.
Low-level Bit Manipulation Solution
To address the permission callback issues caused by nested Fragments, the development team implemented a low-level solution based on bit manipulation operations. Although the specific implementation details involve complex bitwise operations, the core concept involves manually managing permission request codes and callback identifiers to ensure callbacks are correctly routed to the target Fragment.
The following is a simplified implementation example demonstrating how to resolve nested Fragment permission callback issues through custom request code management:
public class HostedFragment extends CompatFragment {
private static final int PERMISSION_REQUEST_MASK = 0x0000FFFF;
private static final int FRAGMENT_ID_SHIFT = 16;
protected int generatePermissionRequestCode(int baseCode) {
int fragmentId = getFragmentId(); // Obtain unique Fragment identifier
return (fragmentId << FRAGMENT_ID_SHIFT) | (baseCode & PERMISSION_REQUEST_MASK);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
int fragmentId = (requestCode >> FRAGMENT_ID_SHIFT) & 0xFFFF;
int actualRequestCode = requestCode & PERMISSION_REQUEST_MASK;
if (fragmentId == getFragmentId() && actualRequestCode == PERMISSIONS_CODE) {
// Handle permission callback logic
handlePermissionResult(permissions, grantResults);
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void handlePermissionResult(String[] permissions, int[] grantResults) {
for (int i = 0; i < permissions.length; i++) {
if (permissions[i].equals(Manifest.permission.SEND_SMS)) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
onPPSButtonPress();
} else {
// Re-request permission
requestPermissions(new String[]{Manifest.permission.SEND_SMS},
generatePermissionRequestCode(PERMISSIONS_CODE));
}
}
}
}
}
Component Types and Permission Method Selection
Beyond nested Fragment issues, the choice of permission request methods also directly affects callback triggering. In the Support Library, different component types require corresponding permission request methods:
- In
AppCompatActivity, use theActivityCompat.requestPermissionsmethod - In
android.support.v4.app.Fragment, use the Fragment instance'srequestPermissionsmethod directly
If ActivityCompat.requestPermissions is incorrectly used within a Fragment, permission callbacks will be sent directly to the Activity without being passed to the Fragment, which is another common cause of onRequestPermissionsResult not being invoked.
Best Practices and Architectural Recommendations
To avoid similar permission callback issues, consider the following factors during project architecture design:
- Unified Permission Management Base Class: Create unified BaseFragment or BaseActivity classes that encapsulate permission request and callback handling logic
- Request Code Management Strategy: Establish clear request code allocation and management mechanisms to avoid conflicts
- Callback Propagation Verification: Verify callback propagation paths in complex Fragment nesting structures
- Error Handling Mechanisms: Design fallback solutions for permission request failures and callback loss scenarios
Through reasonable architectural design and meticulous permission handling logic, various abnormal situations in the runtime permissions system can be effectively avoided, enhancing application stability and user experience.