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 uniquerequestCode
is passed to identify the launched Activity. - Target Activity Completion: The target Activity performs its task. Upon completion (either successfully or canceled), it sets a
resultCode
and 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 theIntent
containing 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_CODE
is an integer that uniquely identifies this specific request. It’s crucial for distinguishing between multiple calls tostartActivityForResult()
.intent
is theIntent
that 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_OK
is a standard constant indicating successful completion. Other constants likeRESULT_CANCELED
can be used for different outcomes.returnIntent
is anIntent
that 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:
requestCode
matches theREQUEST_CODE
used when launching the target Activity. This ensures you’re handling the result from the correct Activity.resultCode
indicates the outcome of the target Activity. Check forRESULT_OK
,RESULT_CANCELED
, or any other relevant codes.data
is theIntent
that 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));