Keywords: Android Development | Camera Intent | Null Pointer Exception | onActivityResult | ResultCode Validation
Abstract: This article provides an in-depth analysis of the common RuntimeException in Android development: Failure delivering result ResultInfo{who=null, request=1888, result=0, data=null} to activity. Through a typical camera photo capture scenario, it explains the root cause where resultCode returns RESULT_CANCELED (value 0) and data becomes null when users cancel camera operations, leading to NullPointerException. Based on the best practice answer, the article systematically explains the importance of validating both resultCode and data integrity in the onActivityResult method, provides complete solutions in both Java and Kotlin, and compares the advantages and disadvantages of different validation strategies. Finally, it discusses the underlying principles of result delivery in Android Intent mechanisms and best practices for defensive programming.
Problem Background and Error Analysis
In Android application development, implementing camera photo capture functionality is a common requirement. Developers typically launch the camera application using the startActivityForResult method and handle the returned photo data in the onActivityResult callback. However, when users cancel the photo capture operation (such as pressing the back button or cancel button), improper handling of the returned result can cause application crashes.
Root Cause: Missing resultCode and Data Validation
The core issue in the original code is that the onActivityResult method only checks the requestCode while ignoring validation of resultCode and data validity. When users cancel the operation, the system returns resultCode as RESULT_CANCELED (with a value of 0) and the data parameter as null. Directly calling data.getExtras() in this situation throws a NullPointerException.
Complete Solution
Based on best practices, the correct implementation of onActivityResult should include multiple layers of validation:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// First layer: Check if operation was cancelled
if (resultCode != RESULT_CANCELED) {
// Second layer: Check if request code matches
if (requestCode == CAMERA_REQUEST) {
// Third layer: Check if returned data is valid
if (data != null && data.getExtras() != null) {
Bitmap photo = (Bitmap) data.getExtras().get("data");
if (photo != null) {
imageView.setImageBitmap(photo);
} else {
// Handle null bitmap data
Log.w("Camera", "Received null bitmap from camera");
}
} else {
// Handle null data or extras
Log.w("Camera", "No data received from camera");
}
}
} else {
// Handle user cancellation
Log.d("Camera", "User cancelled camera operation");
}
}
Kotlin Implementation
For developers using Kotlin, pay attention to parameter nullability declarations:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode != RESULT_CANCELED) {
if (requestCode == CAMERA_REQUEST) {
data?.extras?.get("data")?.let { photoData ->
(photoData as? Bitmap)?.let { bitmap ->
imageView.setImageBitmap(bitmap)
} ?: run {
Log.w("Camera", "Received non-bitmap data from camera")
}
} ?: run {
Log.w("Camera", "No valid data received from camera")
}
}
} else {
Log.d("Camera", "Camera operation cancelled by user")
}
}
Comparison of Validation Strategies
Different answers propose different validation strategies:
- Best Practice (Answer 1): First checks
resultCode != RESULT_CANCELED, which is the most reasonable approach as it directly handles user cancellation scenarios and avoids unnecessary subsequent validations. - Data Validation Approach (Answer 3): Only checks
data != null. While this prevents null pointer exceptions, it's incomplete because even ifdatais not null,resultCodemight still indicate operation failure. - Kotlin Considerations (Answer 2): Emphasizes the importance of parameter nullability in Kotlin, but needs to be combined with complete validation logic to form a comprehensive solution.
Underlying Mechanisms and Best Practices
Android's startActivityForResult mechanism follows this process:
- Call
startActivityForResult(intent, requestCode)to launch the target Activity - The target Activity sets return results via
setResult(resultCode, data) - The system calls the original Activity's
onActivityResultmethod to deliver results - When users cancel operations, the target Activity typically calls
setResult(RESULT_CANCELED)
Best practices for defensive programming include:
- Always validate
resultCode, distinguishing between success (RESULT_OK), cancellation (RESULT_CANCELED), and custom result codes - Perform null checks on
dataand its contents - Use type-safe approaches for data retrieval and conversion
- Add appropriate logging and error handling
- Consider using more modern APIs like
Activity Result API(AndroidX) to simplify result handling
Extended Application Scenarios
This validation pattern applies not only to camera applications but to all scenarios using startActivityForResult, including:
- File pickers (ACTION_GET_CONTENT, ACTION_OPEN_DOCUMENT)
- Contact selection (ACTION_PICK)
- Location selection (ACTION_PICK)
- Any scenario requiring data retrieval from other applications
Through systematic validation strategies, developers can build more robust Android applications, avoiding crashes caused by user cancellations or abnormal return data.