Passing Data Between Activities with startActivityForResult
Android applications often require navigating between different screens (Activities) and passing data between them. startActivityForResult is a powerful mechanism designed for this purpose, allowing one Activity to launch another and receive a result (and associated data) upon its completion. This tutorial will guide you through the entire process, from launching the secondary Activity to handling the returned data.
Understanding the Workflow
The startActivityForResult workflow consists of these steps:
- Launching Activity: The initiating Activity uses
startActivityForResult()to launch the target Activity. A uniquerequestCodeis passed to identify the launched Activity. - Target Activity Completion: The target Activity performs its task. Upon completion (either successfully or canceled), it sets a
resultCodeand optionally includes data within anIntent. It then callssetResult()andfinish(). - Receiving the Result: The initiating Activity’s
onActivityResult()method is called when the target Activity finishes. This method receives therequestCode,resultCode, and theIntentcontaining any returned data.
Launching an Activity with startActivityForResult
To launch a secondary Activity and expect a result, use the startActivityForResult() method.
int REQUEST_CODE = 1; // Define a unique request code
Intent intent = new Intent(this, SecondActivity.class);
startActivityForResult(intent, REQUEST_CODE);
Here:
REQUEST_CODEis an integer that uniquely identifies this specific request. It’s crucial for distinguishing between multiple calls tostartActivityForResult().intentis theIntentthat specifies the target Activity.startActivityForResult()initiates the launch and prepares your Activity to receive a result.
Setting the Result in the Target Activity
Within the target Activity, after completing its task, you need to set the result using setResult() before calling finish().
Intent returnIntent = new Intent();
returnIntent.putExtra("result", "Some data"); // Add data if needed
setResult(RESULT_OK, returnIntent);
finish();
Here:
RESULT_OKis a standard constant indicating successful completion. Other constants likeRESULT_CANCELEDcan be used for different outcomes.returnIntentis anIntentthat carries any data you want to pass back to the initiating Activity. UseputExtra()to add key-value pairs to the Intent.finish()closes the target Activity and returns control to the initiating Activity.
If the target activity doesn’t need to return any data, you can use:
setResult(RESULT_CANCELED);
finish();
Handling the Result in the Initiating Activity
The initiating Activity must override the onActivityResult() method to handle the result from the target Activity.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE) { // Check the request code
if (resultCode == RESULT_OK) { // Check the result code
String result = data.getStringExtra("result"); // Retrieve data
// Process the result
} else if (resultCode == RESULT_CANCELED) {
// Handle cancellation
}
}
}
Here:
requestCodematches theREQUEST_CODEused when launching the target Activity. This ensures you’re handling the result from the correct Activity.resultCodeindicates the outcome of the target Activity. Check forRESULT_OK,RESULT_CANCELED, or any other relevant codes.datais theIntentthat carries the returned data. UsegetStringExtra(),getIntExtra(), and othergetExtra()methods to retrieve the data.
Example Scenario: Camera Feature Check
Let’s illustrate with a scenario where you launch an Activity to check if a device has a camera.
MainActivity (Initiating Activity):
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CAMERA_CHECK = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// ... Launch the camera check Activity ...
Intent intent = new Intent(this, CameraCheckActivity.class);
startActivityForResult(intent, REQUEST_CAMERA_CHECK);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CAMERA_CHECK) {
if (resultCode == RESULT_OK) {
// Camera is present
// ... Proceed with camera-related functionality ...
} else {
// Camera is not present
// ... Handle the case where the camera is missing ...
}
}
}
}
CameraCheckActivity (Target Activity):
public class CameraCheckActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Check if the device has a camera
if (hasCamera()) {
setResult(RESULT_OK);
} else {
setResult(RESULT_CANCELED);
}
finish();
}
private boolean hasCamera() {
// Implement your camera check logic here
return true; // Replace with actual check
}
}
Modern Alternatives: ActivityResultContracts (Android X)
For newer Android development with AndroidX, consider using ActivityResultContracts and registerForActivityResult() as a more streamlined approach. This removes the need to override onActivityResult() directly. The key benefit is simplifying the code when dealing with results from fragments or from other activities.
ActivityResultLauncher<Intent> launchSomeActivity = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
// your operation...
}
});
// ... Launch the activity ...
launchSomeActivity.launch(new Intent(this, SomeActivity.class));