I use a TabActivity with some tabs,each tab contain a ActvityGroup,each ActivityGroup manage more than one Activity.one of ActivtyGroups have three Activies:A,B and C.
At first A is created,when user click a button in A,it jump to B.
in B there are some important data which can be edited in C,when click a "edit"button in B,it jump to C.
if some data is edited in C,when i click back button,i want modify the same data in B.
what drive me crazy is when i use "finish()" in class C,my app exit directly.
I had searched many solutions on the net,bu none of them fit for my case,I don't know where is wrong,please help me or give me a example of how to use startActivityForResult() in ActivityGroup
here is my group:
public class MyGroup extends ActivityGroup
{
private int ID=0;
private AlertDialog dialog;
private Stack<View>history;
private LocalActivityManager manager;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
history = new Stack<View>();
manager = getLocalActivityManager();
Intent intent = new Intent(this,A.class);
startActivity(intent);
}
#Override
public void startActivity(Intent intent)
{
View view = manager.startActivity(""+ID++,intent).getDecorView();
history.push(view);
setContentView(view);
}
#Override
public void startActivityForResult(Intent intent,int requestCode)
{
// super.startActivityForResult(intent, requestCode);
View view = manager.startActivity(""+ID++,intent).getDecorView();
history.push(view);
setContentView(view);
}
/*
* if user edited data in C.class.
* when C.class finished,refresh data in the B.class
*/
#Override
protected void onActivityResult(int requestCode,int resultCode,Intent data)
{
Log.e("MyGroup","running");
super.onActivityResult(requestCode, resultCode, data);
if(resultCode==RESULT_OK)
{
//modify data in B.java
B subActivity=(B)(manager.getCurrentActivity());
subActivity.handleActivityResult(requestCode, resultCode, data);
}
}
/*
* when press back button, manage which page to show next
* if there is one page in stack,that means when press back button it will
* exit the app,so we add a dialog to notify user whether exit app or not
*/
#Override
public void onBackPressed()
{
int size=history.size();
if ( history.size()>= 2)
{
history.remove(size-1);
setContentView(history.get(size-2));
}
else
{
if(dialog==null)
{
createDialog();
}
dialog.show();
}
}
}
in B.class:
public void nextPage()
{
Intent intent=new Intent(B.this,C.class);
intent.putExtra("name", productAdapter.getName(position));
intent.putExtra("id", productAdapter.getID(position));
B.this.getParent().startActivityForResult(intent,11);
}
/*
* modify data in modifyItem
*/
public void handleActivityResult(int requestCode,int resultCode,Intent data)
{
String price=data.getExtras().getString("price");
String name=data.getExtras().getString("name");
String quantity=data.getExtras().getString("quantity");
productAdapter.setName(name, modifyItem);
productAdapter.setPrice(price, modifyItem);
productAdapter.setQuantity(quantity, modifyItem);
productAdapter.notifyDataSetChanged();
}
in C.class:
#Override
public void onBackPressed()
{
if(price!=null)
{
Bundle bundle=new Bundle();
bundle.putString("name",name);
bundle.putString("price",price);
bundle.putString("quantity",quantity);
this.getParent().setResult(RESULT_OK,new Intent().putExtras(bundle));
this.finish();
Log.e("C","inner");
}
Log.e("C","outer");
this.getParent().onBackPressed();
}
Why do you call finish? Pressing back means it will destroy
Your Activity from a ActivityGroup will not get the response calls directly.
You need to redirect from ActivityGroup.
Please see the below answer
Here is the solution. Please try this
https://stackoverflow.com/a/15047518/1403112
Related
I have simple activity with one button. When button is clicked, I'm firing intent to pick image from gallery. Something strange is going on when I fire intent and then rotate the screen. Here are the steps:
Click button. "Open with" system dialog appears.
Rotate screen. Activity gets recreated, dialog is still shown. Note - I don't call startActivityForResult(Intent, int) again on my activity recreate.
Tap back button. "Open with" dialog disappear, but there is another one beneath it.
So it seems even though I don't call startActivityForResult(Intent, int), new instance of dialog gets created every orientation change, and old instance don't getting destroyed.
Does anyone facing this issue? How to get rid of these duplicate dialogs?
Update 1:
So, here is some sample code:
public class MainActivity extends AppCompatActivity
{
private boolean mIsStarted = false;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null)
{
mIsStarted = savedInstanceState.getBoolean("key");
}
if (!mIsStarted)
{
mIsStarted = true;
Intent intent = new Intent(Intent.ACTION_PICK).setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MimeType.IMAGE);
startActivityForResult(intent, 1);
}
}
#Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putBoolean("key", mIsStarted);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
mIsStarted = false;
}
}
I also tried to set android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc" and still every time I rotate the screen, new copy of dialog (actually this is not a dialog, this is ResolverActivity) being showed on top of previous one. Is this some Android bug or it's just me doing something wrong?
Update 2: so I tried another approach - call finishActivity(int) inside my Activity.onStop(). Result is pretty strange - now I've got only 2 copies of ChooserActivity. After second copy is created, it starts rotating fine.
Here is the code:
public class MainActivity extends AppCompatActivity
{
private static final String LOG_TAG = MainActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState)
{
Log.d(LOG_TAG, "onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.make_photo).setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
Intent intent = new Intent(Intent.ACTION_PICK).setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MimeType.IMAGE);
startActivityForResult(intent, 1);
}
});
}
#Override
protected void onStop()
{
Log.d(LOG_TAG, "onStop");
super.onStop();
finishActivity(1);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
Log.d(LOG_TAG, String.format("onActivityResult[requestCode:%d, resultCode:%d, data:%s]",
requestCode, resultCode, data != null ? data.toString() : "NULL"));
}
}
Still wonder why second copy is being created.
Add this to the activity declatation in your androidmanifest.xml
android:configChanges="orientation|screenSize"
This will prevent the activity from getting recreated and resolve the issue of duplicate dialog.
Find out this was silly mistake in my base Activity class. I end up with deriving all my Activities which works with intents from this base IntentProcessingActivity class.
/**
* Base activity for all activities which process intents. This activity saves processing state
* during recreation, so derived activities can get rid of this. This is useful for not showing
* "Open with" dialogs multiple times.
* <p />
* Derived activities can check if some intent is currently processing with {#link
* #isProcessingIntent()} function.
* <p />
* Created by Maksimov Stanislav (s.maks04#gmail.com) on 25.01.16
*/
public class IntentProcessingActivity extends AppCompatActivity
{
private static final String KEY_IS_PROCESSING_INTENT = "IsProcessingIntent";
private boolean mIsProcessingIntent;
#CallSuper
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (savedInstanceState != null)
{
mIsProcessingIntent = savedInstanceState.getBoolean(KEY_IS_PROCESSING_INTENT, false);
}
}
#CallSuper
#Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putBoolean(KEY_IS_PROCESSING_INTENT, mIsProcessingIntent);
}
#CallSuper
#Override
public void startActivityForResult(Intent intent, int requestCode, Bundle options)
{
mIsProcessingIntent = true;
super.startActivityForResult(intent, requestCode, options);
}
#CallSuper
#Override
public void startActivityForResult(Intent intent, int requestCode)
{
mIsProcessingIntent = true;
super.startActivityForResult(intent, requestCode);
}
#CallSuper
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
mIsProcessingIntent = false;
super.onActivityResult(requestCode, resultCode, data);
}
protected final boolean isProcessingIntent()
{
return mIsProcessingIntent;
}
}
On child Activities I just check
if (!isProcessingIntent())
{
startActivityForResult(...);
}
I am making a game, and i want to use the same Activity every time when a user fails the Level and i don't wanna create all the Views every time when the FailedActivity is shown.
For example i have Level1Activity:
public class Level1Activity extends Activity{
private static final int REQUEST_FAIL_ACTIVITY = 10;
private static final int RESULT_RETRY_LEVEL= 11;
public void onCreate(Bundle savedIntanceState){
...
}
public void showFailedActivity(){
Intent intent = new Intent(this, FailedActivity);
intent.putExtra("text1", "You failed! You made only 50 points");
intent.putExtra("text2", "Try again later");
startActivityForResult(intent, REQUEST_FAIL_ACTIVITY );
}
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_FAIL_ACTIVITY ){
if(resultCode == RESULT_BACK){
finish();
}else if(resultCode == RESULT_RETRY_LEVEL){
retryLevel();
}else{
finish();
}
}
}
}
And class FailedActivity
private RelativeLayout bgLayout;
private TextView text1;
private TextView text2;
private TextView text3;
private TextView text4;
private TextView text5;
private Button buttonRetryLevel;
private Button buttonBack;
public class FailedActivity extends Activity{
public void onCreate(Bundle saved){
super.onCreate(saved)
setContentView(R.layout.activity_failed);
bgLayout = (RelativeLayout)findViewById(R.id.bgLayout);
text1 = (TextView)findViewById(R.id.textView1);
...
buttonBack = (Button)findViewById(R.id.btnBack);
Bundle bundle = getIntent().getExtras();
text1.setText(bundle.getString("text1");
...
text5.setText(bundle.getString("text5);
}
public void buttonRetryClicked(View view){
setResult(Level1Activity.RESULT_RETRY_LEVEL);
finish();
}
...
}
So, i want to call findViewById for all the Views only once, and reuse the Activity because the FailedActivity i use for all my Levels, i need to pass only the Strings that will be shown, maybe the background color, etc.
My question is: can i create the FailedActivity only ones, and then when i call startActivityForResult just to pass the Bundle and the Views to be created only once.
You can use
singleInstance
as launch mode and override onNewIntent() function to bypass the re-creation of the activity UI components.
#Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
// handle parameters here.
}
Yes, this is possible as noted in the another answer. If you do this though, you are stepping outside of the standard Activity lifecycle. Generally, when an android app starts a new Activity, the old Activity is destroyed and a new instance of the new one is created. This also occurs when you change the device orientation (portrait -> landscape). The Android runtime does this for memory efficiency and because the view dimensions may have changed. Have a look at this if you want to learn more about the activity lifecycle.
Are the bundled values you're putting in an intent from your Level1Activity going to be the same for other levels? If so you could hardcode those strings directly into the xml layout file for FailedActivity. If you need all level activities to have the ability to open the FailedActivity, I'd consider creating a levelActivity superclass. This will simplify the FailedActivity creation code and stop you from having to repeat yourself. Something like this:
public abstract class LevelActivity extends Activity {
public void showFailedActivity(){
Intent intent = new Intent(this, FailedActivity);
intent.putExtra("text1", "You failed! You made only 50 points");
intent.putExtra("text2", "Try again later");
startActivityForResult(intent, REQUEST_FAIL_ACTIVITY );
}
}
public class Level1Activity extends LevelActivity {
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_FAIL_ACTIVITY ){
if(resultCode == RESULT_BACK){
finish();
}else if(resultCode == RESULT_RETRY_LEVEL){
super.retryLevel(); // calls LevelActivity.retryLevel()
}else{
finish();
}
}
}
Is it possible to call startActivityForResult() from a non-activity class to get the results?
Scenario is something like this:
I have a class NonActivity (it doesn't derive from Activity as its not a UI).
This class will have bunch of functions(steps basically) to run.
One of the steps requires to show UI(Activity) and then get the result (user enter something).
Then been able to use that data in next following steps.
How can this be achieved without deriving from activity class as I don't have UI component?
Also since I don't want to derive from activity class that means I cannot override OnActivityResult(). Where results actually come from?
startActivityForResult() is only available from real on-screen activities, since it is a method in, well, Activity. Please redesign your application so that the user interface is driven from activities.
On the other hand, if your non Activity class is initialized and used from an onscreen Activity, you could pass that instance of the Activity to your class as a parameter in the constructor and use it to launch other Activities.
Be careful though. Using this method increases the risk of a memory leak, as the external class (Utils in my example) might keep a reference to the Activity even after its gone.
If all you want to do is access data, then you could try writing it to SharedPreferences or a Database or some files and then using the application context (passed in via a constructor again) to read it. This reduces the risk of a memory leak. Something like:
MyApiClass myApiClass = new MyApiClass(getApplicationContext());
EXAMPLE CODE
Main Activity:
public class Main extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Utils util = new Utils(this);
util.startTest();
}
#Override
protected void onActivityResult(int arg0, int arg1, Intent arg2) {
Toast.makeText(this, "onActivityResult called", Toast.LENGTH_LONG).show();
super.onActivityResult(arg0, arg1, arg2);
}
}
Utils class (which launches for result):
public class Utils {
Activity activity;
public Utils(Activity ac) {
activity = ac;
}
public void startTest() {
Intent i = new Intent(activity, Test.class);
activity.startActivityForResult(i, 1);
}
}
Test Activity:
public class Test extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toast.makeText(this, "Test", Toast.LENGTH_LONG).show();
this.setResult(Activity.RESULT_OK);
this.finish();
}
}
StartActivityForResult from a class using a fragment with no visible GUI. You might find something like this in a utility class.
see runGetUserAccount below. It creates its own fragment and executes a startActivityForResult. Then it has it's own onActivityResult.
public class MyGooglePlay {
private static final int CONNECTION_FAILURE_RESOLUTION_REQUEST = 31502;
private ActionBarActivity activity;
private FragmentManager fragManager;
public MyGooglePlay(ActionBarActivity activity) {
this.activity = activity;
this.fragManager = activity.getSupportFragmentManager();
}
/**
* Starts an activity in Google Play Services so the user can pick an
* account
*/
private String mEmail = "";
static final int REQUEST_CODE_PICK_ACCOUNT = 1000;
public void runGetUserAccount() {
if (TextUtils.isEmpty(mEmail)) {
// run this code in gui less fragment so we can pickup the
// on activity result from inside the mygoogleplay class.
Fragment f = new Fragment() {
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
String[] accountTypes = new String[] { "com.google" };
Intent intent = AccountPicker.newChooseAccountIntent(null,
null, accountTypes, false, null, null, null, null);
startActivityForResult(intent, REQUEST_CODE_PICK_ACCOUNT);
}
#Override
public void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == REQUEST_CODE_PICK_ACCOUNT) {
if (resultCode == Activity.RESULT_OK) {
set_Email(data
.getStringExtra(AccountManager.KEY_ACCOUNT_NAME));
// getUsername();
}
super.onActivityResult(requestCode, resultCode, data);
}
//this is to verify the fragment has been removed.
//you can log or put a breakpoint to verify
#Override public void onDestroy(){
super.onDestroy();
}
};
FragmentTransaction fragmentTransaction = this.fragManager
.beginTransaction();
fragmentTransaction.add(f, "getusername");
fragmentTransaction.commit();
}
}
/**
* #param mEmail
* the mEmail to set
*/
private void set_Email(String mEmail) {
this.mEmail = mEmail;
if (!TextUtils.isEmpty(mEmail)) {
// TODO notify caller email is ready;
// activity.onEmailReady(mEmail);
}
//we are done with the "getusername" fragment
Fragment f = fragManager.findFragmentByTag("getusername");
if (f!=null) {
fragManager.beginTransaction().remove(f).commit();
}
}
}
U should pass context as Activity,then u will get solution.
try this below code.it will work
In non Activity class
public class nonActivity {
public static void method(Activity activity)
{
Intent intent = new Intent(activity, SecondActivity.class);
activity. startActivityForResult(intent, REQUEST_CODE);
}
}
In SecondActivity
Intent intent = getIntent();
intent.putExtra("data", "data"); //here u can pass data to previous activity
setResult(RESULT_OK, intent);
finish();
In firstActivity
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
try {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
String status = data.getStringExtra("data");
//Do what u want with data
}
} catch (Exception e) {
System.out.println("=====Exception=====" + e.toString());
}
}
If you want the result back from the activity to your normal class, supposed it is a class with a custom adapter within it.
you cannot use startActivityForResult because you are not in an activity
what I did is that i launched the activity from the class with an intent. Then I calculated or did what I have to. From this activity I send the information to the main class supposed with a method MainActivity.the_method() and in the main activity I changed the custom adapter o did what I have to using the adapter object and calling adapter.getItem(position)
Hope this can give you an idea
I don't know why this is so difficult to figure out. I have my main activity that, when launched, checks if this is the first time it's been opened. If it is, then it closes the main activity and opens the setup/introduction activity with FLAG_ACTIVITY_NEW_TASK. The setup process consists of three activities (A, B, and C). At the end of activity C, how do I get it to clear and the setup task that contains A, B, and C and start the main activity again. I've tried adding FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP to main activity Intent but when I press BACK, it returns to activity C of the setup process. How do I get it to clear the task of activities A, B, and C when C finishes and starts the main? Thanks!
I'm building in Android 1.6 (API 4), so some of the Activity flags may be limited.
FLAG_ACTIVITY_CLEAR_TOP will clear activities it it is of the same activity instance. Here in your case all your activities are of different instances so FLAG_ACTIVITY_CLEAR_TOP won't work. To clear your task, create an Activity instance in each of your activity and assign that instance 'this' on your onCreate method of every activity. whenever you want to clear your task jus call that instance.finish(). and start the activity that you want.
Actually this can be achieved with startActivityForResult
public class A extends Activity {
public onButtonClick() {
startActivityForResult(new Intent(this, B.class), 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
finish();
}
}
}
public class B extends Activity {
public onButtonClick() {
startActivityForResult(new Intent(this, C.class), 0);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
setResult(RESULT_OK);
finish();
}
}
}
public class C extends Activity {
public onButtonClick() {
setResult(RESULT_OK);
finish();
}
}
I think this is the right way, you don't leak anything this way.
PS: I know this is old post, but maybe someone will find this useful.
I answered a similar question here
As Mudassir says in their comment just finish() your activities immediately after starting a new one.
class A extends Activity {
public static Activity instanceOfA = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
instanceOfA = this;
}
}
class b extends Activity {
public static Activity instanceOfB = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
instanceOfB = this;
}
}
class c extends Activity {
public static Activity instanceOfC = null;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
instanceOfC = this;
}
}
Now suppose you want to clear all the task from your current activity, then call
instanceOfA.finish();
instanceOfB.finish();
instanceOfC.finish();
I have two activities: main activity and child activity.
When I press a button in the main activity, the child activity is launched.
Now I want to send some data back to the main screen. I used the Bundle class, but it is not working. It throws some runtime exceptions.
Is there any solution for this?
There are a couple of ways to achieve what you want, depending on the circumstances.
The most common scenario (which is what yours sounds like) is when a child Activity is used to get user input - such as choosing a contact from a list or entering data in a dialog box. In this case, you should use startActivityForResult to launch your child Activity.
This provides a pipeline for sending data back to the main Activity using setResult. The setResult method takes an int result value and an Intent that is passed back to the calling Activity.
Intent resultIntent = new Intent();
// TODO Add extras or a data URI to this intent as appropriate.
resultIntent.putExtra("some_key", "String data");
setResult(Activity.RESULT_OK, resultIntent);
finish();
To access the returned data in the calling Activity override onActivityResult. The requestCode corresponds to the integer passed in the startActivityForResult call, while the resultCode and data Intent are returned from the child Activity.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case (MY_CHILD_ACTIVITY) : {
if (resultCode == Activity.RESULT_OK) {
// TODO Extract the data returned from the child Activity.
String returnValue = data.getStringExtra("some_key");
}
break;
}
}
}
Activity 1 uses startActivityForResult:
startActivityForResult(ActivityTwo, ActivityTwoRequestCode);
Activity 2 is launched and you can perform the operation, to close the Activity do this:
Intent output = new Intent();
output.putExtra(ActivityOne.Number1Code, num1);
output.putExtra(ActivityOne.Number2Code, num2);
setResult(RESULT_OK, output);
finish();
Activity 1 - returning from the previous activity will call onActivityResult:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ActivityTwoRequestCode && resultCode == RESULT_OK && data != null) {
num1 = data.getIntExtra(Number1Code);
num2 = data.getIntExtra(Number2Code);
}
}
UPDATE:
Answer to Seenu69's comment, In activity two,
int result = Integer.parse(EditText1.getText().toString())
+ Integer.parse(EditText2.getText().toString());
output.putExtra(ActivityOne.KEY_RESULT, result);
Then in activity one,
int result = data.getExtra(KEY_RESULT);
Sending Data Back
It helps me to see things in context. Here is a complete simple project for sending data back. Rather than providing the xml layout files, here is an image.
Main Activity
Start the Second Activity with startActivityForResult, providing it an arbitrary result code.
Override onActivityResult. This is called when the Second Activity finishes. You can make sure that it is actually the Second Activity by checking the request code. (This is useful when you are starting multiple different activities from the same main activity.)
Extract the data you got from the return Intent. The data is extracted using a key-value pair.
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final int SECOND_ACTIVITY_REQUEST_CODE = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// "Go to Second Activity" button click
public void onButtonClick(View view) {
// Start the SecondActivity
Intent intent = new Intent(this, SecondActivity.class);
startActivityForResult(intent, SECOND_ACTIVITY_REQUEST_CODE);
}
// This method is called when the second activity finishes
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Check that it is the SecondActivity with an OK result
if (requestCode == SECOND_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// Get String data from Intent
String returnString = data.getStringExtra("keyName");
// Set text view with string
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(returnString);
}
}
}
}
Second Activity
Put the data that you want to send back to the previous activity into an Intent. The data is stored in the Intent using a key-value pair.
Set the result to RESULT_OK and add the intent holding your data.
Call finish() to close the Second Activity.
SecondActivity.java
public class SecondActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
// "Send text back" button click
public void onButtonClick(View view) {
// Get the text from the EditText
EditText editText = (EditText) findViewById(R.id.editText);
String stringToPassBack = editText.getText().toString();
// Put the String to pass back into an Intent and close this activity
Intent intent = new Intent();
intent.putExtra("keyName", stringToPassBack);
setResult(RESULT_OK, intent);
finish();
}
}
Other notes
If you are in a Fragment it won't know the meaning of RESULT_OK. Just use the full name: Activity.RESULT_OK.
See also
Fuller answer that includes passing data forward
Naming Conventions for the Key String
FirstActivity uses startActivityForResult:
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivityForResult(intent, int requestCode); // suppose requestCode == 2
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 2)
{
String message=data.getStringExtra("MESSAGE");
}
}
On SecondActivity call setResult() onClick events or onBackPressed()
Intent intent=new Intent();
intent.putExtra("MESSAGE",message);
setResult(Activity.RESULT_OK, intent);
Call the child activity Intent using the startActivityForResult() method call
There is an example of this here:
http://developer.android.com/training/notepad/notepad-ex2.html
and in the "Returning a Result from a Screen" of this:
http://developer.android.com/guide/faq/commontasks.html#opennewscreen
UPDATE Mar. 2021
As in Activity v1.2.0 and Fragment v1.3.0, the new Activity Result APIs have been introduced.
The Activity Result APIs provide components for registering for a result, launching the result, and handling the result once it is dispatched by the system.
So there is no need of using startActivityForResult and onActivityResult anymore.
In order to use the new API, you need to create an ActivityResultLauncher in your origin Activity, specifying the callback that will be run when the destination Activity finishes and returns the desired data:
private val intentLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
result.data?.getStringExtra("key1")
result.data?.getStringExtra("key2")
result.data?.getStringExtra("key3")
}
}
and then, launching your intent whenever you need to:
intentLauncher.launch(Intent(this, YourActivity::class.java))
And to return data from the destination Activity, you just have to add an intent with the values to return to the setResult() method:
val data = Intent()
data.putExtra("key1", "value1")
data.putExtra("key2", "value2")
data.putExtra("key3", "value3")
setResult(Activity.RESULT_OK, data)
finish()
For any additional information, please refer to Android Documentation
I have created simple demo class for your better reference.
FirstActivity.java
public class FirstActivity extends AppCompatActivity {
private static final String TAG = FirstActivity.class.getSimpleName();
private static final int REQUEST_CODE = 101;
private Button btnMoveToNextScreen;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnMoveToNextScreen = (Button) findViewById(R.id.btnMoveToNext);
btnMoveToNextScreen.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent mIntent = new Intent(FirstActivity.this, SecondActivity.class);
startActivityForResult(mIntent, REQUEST_CODE);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
if(requestCode == REQUEST_CODE && data !=null) {
String strMessage = data.getStringExtra("keyName");
Log.i(TAG, "onActivityResult: message >>" + strMessage);
}
}
}
}
And here is SecondActivity.java
public class SecondActivity extends AppCompatActivity {
private static final String TAG = SecondActivity.class.getSimpleName();
private Button btnMoveToPrevious;
private EditText editText;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
editText = (EditText) findViewById(R.id.editText);
btnMoveToPrevious = (Button) findViewById(R.id.btnMoveToPrevious);
btnMoveToPrevious.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String message = editText.getEditableText().toString();
Intent mIntent = new Intent();
mIntent.putExtra("keyName", message);
setResult(RESULT_OK, mIntent);
finish();
}
});
}
}
In first activity u can send intent using startActivityForResult() and then get result from second activity after it finished using setResult.
MainActivity.class
public class MainActivity extends AppCompatActivity {
private static final int SECOND_ACTIVITY_RESULT_CODE = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// "Go to Second Activity" button click
public void onButtonClick(View view) {
// Start the SecondActivity
Intent intent = new Intent(this, SecondActivity.class);
// send intent for result
startActivityForResult(intent, SECOND_ACTIVITY_RESULT_CODE);
}
// This method is called when the second activity finishes
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// check that it is the SecondActivity with an OK result
if (requestCode == SECOND_ACTIVITY_RESULT_CODE) {
if (resultCode == RESULT_OK) {
// get String data from Intent
String returnString = data.getStringExtra("keyName");
// set text view with string
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(returnString);
}
}
}
}
SecondActivity.class
public class SecondActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
// "Send text back" button click
public void onButtonClick(View view) {
// get the text from the EditText
EditText editText = (EditText) findViewById(R.id.editText);
String stringToPassBack = editText.getText().toString();
// put the String to pass back into an Intent and close this activity
Intent intent = new Intent();
intent.putExtra("keyName", stringToPassBack);
setResult(RESULT_OK, intent);
finish();
}
}
All these answers are explaining the scenario of your second activity needs to be finish after sending the data.
But in case if you don't want to finish the second activity and want to send the data back in to first then for that you can use BroadCastReceiver.
In Second Activity -
Intent intent = new Intent("data");
intent.putExtra("some_data", true);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
In First Activity-
private BroadcastReceiver tempReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do some action
}
};
Register the receiver in onCreate()-
LocalBroadcastManager.getInstance(this).registerReceiver(tempReceiver,new IntentFilter("data"));
Unregister it in onDestroy()
Another way of achieving the desired result which may be better depending on your situation is to create a listener interface.
By making the parent activity listen to an interface that get triggered by the child activity while passing the required data as a parameter can create a similar set of circumstance
There are some ways of doing this.
1. by using the startActivityForResult() which is very well explained in the above answers.
by creating the static variables in your "Utils" class or any other class of your own. For example i want to pass studentId from ActivityB to ActivityA.First my ActivityA is calling the ActivityB. Then inside ActivityB set the studentId (which is a static field in Utils.class).
Like this Utils.STUDENT_ID="1234"; then while comming back to the ActivityA use the studentId which is stored in Utils.STUDENT_ID.
by creating a getter and setter method in your Application Class.
like this:
public class MyApplication extends Application {
private static MyApplication instance = null;
private String studentId="";
public static MyApplication getInstance() {
return instance;
}
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
public void setStudentId(String studentID){
this.studentId=studentID;
}
public String getStudentId(){
return this.studentId;
}
}
so you are done . just set the data inside when u are in ActivityB and after comming back to ActivityA , get the data.
Just a small detail that I think is missing in above answers.
If your child activity can be opened from multiple parent activities then you can check if you need to do setResult or not, based on if your activity was opened by startActivity or startActivityForResult. You can achieve this by using getCallingActivity(). More info here.
Use sharedPreferences and save your data and access it from anywhere in the application
save date like this
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(key, value);
editor.commit();
And recieve data like this
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
String savedPref = sharedPreferences.getString(key, "");
mOutputView.setText(savedPref);