How to Use startActivityForResult() in Android – A Step-by-Step Guide
Introduction
In Android development, it’s very common to pass data between activities. Activities are the building blocks of an Android application, and often you need to move from one activity to another while sending and receiving information. The most popular way to achieve this is by using Intent and methods like startActivityForResult() and onActivityResult().
In this detailed tutorial, we will walk through the process of:
- Sending data from one activity to another.
- Receiving the data back from the second activity to the first.
We will demonstrate this by creating two activities:
- MainActivity: The primary screen where users can click a button to open another activity.
- SecondActivity: A secondary screen where users can input some data, which will be sent back to the first activity.
This tutorial will give you a clear understanding of how to pass data between Android activities and handle the result. By the end of this, you’ll be able to use this technique in your own Android projects when you need to pass data between activities.
Let’s begin by explaining the concept and the workflow step-by-step.
What Are Intent and startActivityForResult()?
- Intent: An
Intentin Android is used to communicate between different components of the app, like activities, services, or broadcast receivers. You can think of anIntentas a message that tells the system to perform a particular action, such as opening another activity or passing data. - startActivityForResult(): This method is used when you want to start a new activity and get a result back from it. Unlike
startActivity(), which simply opens another activity,startActivityForResult()allows the launched activity to return data to the calling activity once it’s finished. - onActivityResult(): This is the method where you handle the data that is returned from the launched activity. Once the second activity finishes, it returns the result (such as some user input) through this method.
The core idea behind this pattern is that the first activity sends data to the second activity, and the second activity sends some result back. This communication is essential in scenarios like collecting user input, selecting items from a list, or confirming a decision.
Step 2: Setting Up MainActivity to Send Data to SecondActivity
In this part of the tutorial, we will set up the MainActivity. This activity will contain a button that, when clicked, opens SecondActivity and expects a result back. Let’s walk through the code and explain how everything works.
2.1: Create the Layout for MainActivity
First, we need to define the layout for MainActivity. The layout will consist of:
- A
TextViewto display the data received from SecondActivity. - A
Buttonthat, when clicked, opens SecondActivity.
Here’s how you can define the layout in XML:
<!-- activity_main.xml -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- TextView to display data received from SecondActivity -->
<TextView
android:id="@+id/display"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Data will appear here"
android:layout_centerInParent="true"/>
<!-- Button to open SecondActivity -->
<Button
android:id="@+id/gotosecond"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go to Second Activity"
android:layout_below="@id/display"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"/>
</RelativeLayout>
In this layout:
- The
TextViewis used to display the result coming back from SecondActivity. - The
Buttonwill trigger the transition to SecondActivity.
2.2: Implement the Code for MainActivity
Now let’s implement the logic in MainActivity. The steps are as follows:
- Find Views: We will find the
TextViewandButtonusingfindViewById(). - Set Click Listener for the Button: When the button is clicked, we’ll create an
Intentto open SecondActivity. - Use
startActivityForResult(): This method will allow us to launch SecondActivity and expect a result back. - Handle the Result in
onActivityResult(): Once SecondActivity finishes, we will get the result back in this method.
Here’s the Java code for MainActivity:
package com.developeravsk.intentwithresult;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
TextView tv; // TextView to display the data received
Button go; // Button to trigger the opening of SecondActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // Set the layout for this activity
// Find the views
tv = findViewById(R.id.display);
go = findViewById(R.id.gotosecond);
// Set an OnClickListener for the button
go.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Create an Intent to open SecondActivity
Intent i = new Intent(MainActivity.this, SecondActivity.class);
// Start SecondActivity and expect a result back
startActivityForResult(i, 1); // 1 is the requestCode
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Check if the result is from the expected requestCode
if (requestCode == 1 && resultCode == RESULT_OK) {
// Get the data sent back from SecondActivity
String myData = data.getStringExtra("data");
// Update the TextView with the received data
tv.setText(myData);
}
}
}
Explanation of Code:
- Finding Views:
- We use
findViewById()to get references to theTextViewandButton. TheTextViewis where we will display the data from the second activity, and theButtonwill trigger the opening of the second activity.
- We use
- Button OnClickListener:
- We set an
OnClickListenerfor the button. When the button is clicked, anIntentis created to open SecondActivity.
- We set an
- startActivityForResult():
startActivityForResult(i, 1)is called to open SecondActivity. The1is a request code that identifies the request. It allows us to distinguish between different activity results if we have multiple activities that could return data.
- onActivityResult():
- After SecondActivity completes, the data sent back is received in
onActivityResult(). We check if therequestCodeis1(which matches ourstartActivityForResult()request) and if theresultCodeisRESULT_OK. Then we retrieve the data sent back usingdata.getStringExtra("data")and update theTextView.
- After SecondActivity completes, the data sent back is received in
Step 3: Setting Up SecondActivity to Send Data Back to MainActivity
In this part of the tutorial, we will implement SecondActivity. This activity will allow the user to input some data, and when the user presses the “Go Back” button, the data will be sent back to MainActivity.
3.1: Create the Layout for SecondActivity
We need to design the layout for SecondActivity. The layout will include:
- An
EditTextfield where users can type in some data. - A
Buttonto send the data back to MainActivity.
Here’s how you can define the layout in XML:
<!-- activity_second.xml -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- EditText for user input -->
<EditText
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter some data"
android:layout_centerInParent="true"
android:padding="16dp"/>
<!-- Button to send data back to MainActivity -->
<Button
android:id="@+id/goback"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go Back"
android:layout_below="@id/et"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"/>
</RelativeLayout>
In this layout:
- The
EditTextis where the user will type some data. - The
Buttonwill allow the user to return to MainActivity and send the input data back.
3.2: Implement the Code for SecondActivity
Now let’s implement the logic in SecondActivity. The steps are as follows:
- Find Views: We will find the
EditTextandButtonusingfindViewById(). - Set Click Listener for the Button: When the button is clicked, we will gather the data from the
EditTextand send it back to MainActivity. - Use
setResult(): This method will send the result back to the calling activity. - Finish the Activity: After sending the data back, we will call
finish()to close SecondActivity and return to MainActivity.
Here’s the Java code for SecondActivity:
package com.developeravsk.intentwithresult;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
public class SecondActivity extends AppCompatActivity {
EditText data; // EditText to take user input
Button goback; // Button to send data back to MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second); // Set the layout for this activity
// Find the views
data = findViewById(R.id.et);
goback = findViewById(R.id.goback);
// Set an OnClickListener for the button
goback.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Get the data entered by the user
String userData = data.getText().toString();
// Create an Intent to send data back to MainActivity
Intent i = new Intent();
i.putExtra("data", userData); // Attach the data to the Intent
// Set the result with the data
setResult(RESULT_OK, i); // RESULT_OK indicates success
// Finish the activity and go back to MainActivity
finish();
}
});
}
}
Explanation of Code:
- Finding Views:
- We use
findViewById()to get references to theEditTextandButton. TheEditTextis where the user will type the data to send back, and theButtonwill trigger sending the data.
- We use
- Button OnClickListener:
- We set an
OnClickListenerfor the button. When the button is clicked, we retrieve the text entered in theEditTextusingdata.getText().toString().
- We set an
- Creating the Intent:
- We create an
Intentobject that will be used to send the data back to MainActivity. i.putExtra("data", userData)attaches the user input to the intent. The key"data"will be used to retrieve the data in MainActivity.
- We create an
- Sending the Result:
- We use
setResult(RESULT_OK, i)to send the result back to the calling activity (MainActivity). TheRESULT_OKindicates that the result was successful. If you wanted to indicate failure, you would useRESULT_CANCELEDinstead.
- We use
- Finish the Activity:
- Finally,
finish()is called to close SecondActivity and return to MainActivity. When this happens, MainActivity will receive the result inonActivityResult().
- Finally,
Step 4: Receiving Data in MainActivity and Displaying It
Now that we’ve successfully set up SecondActivity to send data back, the next step is to handle the returned data in MainActivity and display it on the screen.
4.1: Handling the Returned Data
When SecondActivity finishes and sends data back to MainActivity, we need to catch the result and handle it appropriately. This is done by overriding the onActivityResult() method in MainActivity.
Here’s how the data flow works:
- MainActivity sends an intent to SecondActivity to gather data.
- SecondActivity lets the user input data, and once they click the button, it sends the data back using
setResult()andfinish(). - MainActivity receives the result in
onActivityResult()and displays it on the screen.
4.2: Implementing onActivityResult() in MainActivity
In MainActivity, we need to override the onActivityResult() method to capture the data sent back from SecondActivity.
Here’s how the updated code for MainActivity looks:
package com.developeravsk.intentwithresult;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
TextView tv; // TextView to display the data returned
Button go; // Button to open SecondActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // Set the layout for this activity
// Find the views
tv = findViewById(R.id.display); // The TextView to display returned data
go = findViewById(R.id.gotosecond); // Button to go to SecondActivity
// Set an OnClickListener for the button
go.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Create an Intent to open SecondActivity
Intent i = new Intent(MainActivity.this, SecondActivity.class);
startActivityForResult(i, 1); // Start SecondActivity and expect a result
}
});
}
// This method is called when SecondActivity finishes and sends back the result
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Check if the requestCode matches and the result was OK
if (requestCode == 1 && resultCode == RESULT_OK) {
// Retrieve the data sent back from SecondActivity
String myData = data.getStringExtra("data");
// Display the data on the TextView
tv.setText(myData);
}
}
}
Explanation of Code:
- Finding Views:
- We find the
TextView(tv) and theButton(go) usingfindViewById(). TheTextViewwill be used to display the data received from SecondActivity.
- We find the
- Sending Data to
SecondActivity:- When the button is clicked, we create an
Intentto launch SecondActivity and usestartActivityForResult()to initiate the intent. This method allows us to specify a request code (in this case,1) to identify the result when it returns.
- When the button is clicked, we create an
- Receiving the Data:
- The
onActivityResult()method is automatically called when SecondActivity finishes and sends data back. TherequestCodeparameter lets us confirm which activity is returning the result (in case we have multiple activities sending results). - If the
requestCodeis1and theresultCodeisRESULT_OK, we retrieve the data usingdata.getStringExtra("data"). This is the data that was sent back from SecondActivity.
- The
- Displaying the Data:
- Finally, we set the returned data (
myData) into theTextView(tv) usingtv.setText(myData).
- Finally, we set the returned data (
4.3: Running the App
- When you run the app, MainActivity will be displayed with a button labeled “Go to Second Activity.”
- When the user clicks the button, SecondActivity opens with an
EditTextfor input and a “Go Back” button. - The user types something in the
EditTextand clicks the “Go Back” button. - The data is sent back to MainActivity, and it will be displayed in the
TextView.
Recap of Data Flow
- MainActivity starts SecondActivity and expects a result (using
startActivityForResult()). - SecondActivity lets the user enter data, and when the “Go Back” button is clicked, it sends the data back to MainActivity using
setResult()andfinish(). - MainActivity receives the data in
onActivityResult()and displays it on the screen.
Step 5: Best Practices and Summary
In this final section, we’ll cover some best practices for using startActivityForResult() and onActivityResult() effectively, and then we’ll summarize the entire process.
5.1: Best Practices for Using startActivityForResult() and onActivityResult()
While working with intents and results in Android, it’s important to follow certain best practices to make your app more efficient, maintainable, and user-friendly:
Use Clear and Meaningful Request Codes:
- It’s important to use request codes that are meaningful to avoid confusion. Instead of using
1for all requests, you could define constants with descriptive names, likeREQUEST_CODE_GET_USER_INPUT. This will make your code more readable and easier to debug.
private static final int REQUEST_CODE_GET_USER_INPUT = 1001;
Handle Edge Cases in onActivityResult():
- Always check for null values in the
dataobject inonActivityResult(). Sometimes, the result may not contain the expected data, and handling such cases gracefully can prevent crashes.
Example:
if (data != null) {
String myData = data.getStringExtra("data");
if (myData != null) {
tv.setText(myData);
} else {
tv.setText("No data returned.");
}
}
Use ActivityResultContracts in Newer Android Versions:
- Starting from Android API level 23 (Android 6.0, Marshmallow),
startActivityForResult()is deprecated in favor ofActivityResultContracts. This new API provides a more modern and flexible approach to handling results and improves readability.
Here’s a basic example using ActivityResultContracts:
ActivityResultLauncher<Intent> resultLauncher =
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == RESULT_OK) {
String data = result.getData().getStringExtra("data");
tv.setText(data);
}
});
go.setOnClickListener(v -> {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
resultLauncher.launch(intent);
});
Using this approach eliminates the need for onActivityResult() and makes the code easier to understand and manage.
Respect User Privacy:
- When collecting data from users, always ensure that you’re following best practices for privacy and data protection. For example, if you’re collecting sensitive information, make sure that it’s stored securely and inform users of what the data will be used for.
Avoid Using onActivityResult() for Long-Term Communication:
- For more complex data passing or long-term interactions between activities, consider using a more robust solution, like ViewModels with LiveData or shared preferences, rather than relying solely on
onActivityResult(). This approach can help decouple the logic between activities.
Always Set a Result:
- Ensure that every time you call
setResult(), you are properly setting a result (e.g.,RESULT_OKorRESULT_CANCELED) in SecondActivity. Otherwise, MainActivity may not know if the activity ended successfully or if there was an issue.
Example:
setResult(RESULT_OK, intent); // Ensure you send back a result code
- Handle Different Activity States:
- Be aware that
onActivityResult()may be called when your activity is paused or stopped (e.g., if the user navigates away from the activity temporarily). Make sure to handle these cases properly by updating the UI in a way that doesn’t rely on the activity being fully resumed.
- Be aware that
5.2: Summary of the Process
In this tutorial, we demonstrated how to pass data between two activities using intents, handle the data in MainActivity, and display it on the UI. Here’s a recap of the main steps involved:
- Sending Data from
MainActivitytoSecondActivity:- We used an
Intentto open SecondActivity and started it for a result withstartActivityForResult().
- We used an
- Collecting Data in
SecondActivity:- SecondActivity allowed the user to input data and then sent the data back to MainActivity using
setResult()andfinish().
- SecondActivity allowed the user to input data and then sent the data back to MainActivity using
- Receiving Data in
MainActivity:- We overrode
onActivityResult()in MainActivity to capture the result and display the returned data in aTextView.
- We overrode
- Best Practices:
- We covered best practices, such as handling null data, using meaningful request codes, and exploring the newer
ActivityResultContractsfor improved result handling.
- We covered best practices, such as handling null data, using meaningful request codes, and exploring the newer
By following these steps, you can efficiently pass data between activities, making your app interactive and dynamic. The approach shown here is fundamental to creating multi-activity applications where activities communicate with each other.
Conclusion
In this tutorial, we’ve explored how to send and receive data between activities using intents in Android. This is a crucial concept for Android developers, especially when building apps with multiple screens or steps in the user flow. By using startActivityForResult() and onActivityResult(), you can easily share data and create a smooth user experience.
As your apps become more complex, consider using ActivityResultContracts to handle results in a more modern and cleaner way. Always follow the best practices to maintain code readability, security, and user privacy.