I have an application that has this transition:

 A -> B -> C -> D-> C

Upon entering C , i have to check a flag. Then I have to pass it as intent (let us say intentX = false) to D. After doing something in D , it will then go back to C after pressing a button. What i did was just pass again the intentX with value true, then startActivity C again. So what happen is that it created another Activity C.

What i want to happen is that i will not have to start a new Activity C, but use the previous C by just calling super.onBackPressed(). But I cannot pass the new value of the intentX. Is there other way, to achieve what i want. I might have missed some.

Solution 1

What you want is startActivityForResult(). When you go from C to D, instead of using startActivity() use instead startActivityForResult(). Then when you want to return from D to C you use setResult() which can include an Intent object with extras to pass back to C.

I don't recommend doing this in onBackPressed() if you don't have to because this will not be what the user expects. Instead, you should return with this data with an event such as a Button click.

So, in C you will do something like

 Intent i = new Intent(new Intent(C.this, D.class);
 startActivityForResult(i, 0);

then in D when you are ready to return

 Intent i = new Intent();
 i.putExtra();  // insert your extras here
 setResult(0, i);

then when you return to C you will enter this method (taken from the Docs)

protected void onActivityResult(int requestCode, int resultCode,
         Intent data) {
     if (requestCode == PICK_CONTACT_REQUEST) {
         if (resultCode == RESULT_OK) {
             // A contact was picked.  Here we will just display it
             // to the user.
             startActivity(new Intent(Intent.ACTION_VIEW, data));

             /* 
                can also get the extra sent back through data
                using data.getStringExtra("someKey"); 
                assuming the extra was a String
             */

         }

Solution 2

There are some cases where startActivityForResult is not really needed or it is not practical to change all startActivity calls for startActivityForResult.

If the simple case of just starting a previous activity 'again' is needed, my recommendation is: Use the FLAG_ACTIVITY_CLEAR_TOP flag.

Quoting a brief description:

If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.

For example, consider a task consisting of the activities: A, B, C, D. If D calls startActivity() with an Intent that resolves to the component of activity B, then C and D will be finished and B receive the given Intent, resulting in the stack now being: A, B.

So this example

   // From ActivityD
   Intent intent = new Intent(getApplicationContext(), ActivityB.class);
   intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // The flag we wanted
   intent.putExtra(ActivityB.SOME_EXTRA_THAT_I_NEED_CHANGED, SomeValue); // Example of changing the intent to get something new..
   startActivity(intent);

Where you will get that new intent is defined by which launch mode and which flags where used to start it (in this case our ActivityB).

The currently running instance of activity B in the above example will either receive the new intent you are starting here in its onNewIntent() method, or be itself finished and restarted with the new intent. If it has declared its launch mode to be "multiple" (the default) and you have not set FLAG_ACTIVITY_SINGLE_TOP in the same intent, then it will be finished and re-created; for all other launch modes or if FLAG_ACTIVITY_SINGLE_TOP is set then this Intent will be delivered to the current instance's onNewIntent().