73

I'm using the recommended approach for Up Navigation and my code looks like this:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            Intent h = new Intent(ShowDetailsActivity.this, MainActivity.class);
            h.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(h);
            return true;
        default: return super.onOptionsItemSelected(item);
    }
}

Here's the use-case:

  1. I launch my app which is "MainActivity"
  2. I click a button to go to "ShowDetailsActivity"
  3. I click on the UP ActionBar navigation

The issue is after I click on UP, MainActivity hits its onCreate() methods all over again and loses all state instead of starting at the typical onResume() like it would if I just called "finish()" from ShowDetailsActivity. Why? Is this how it always works and this is expected behavior for Android to recreate all activities that are navigated to using the "Up" navigation approach? If I hit the back button I get the expected onResume lifecycle.

This is my solution if an Android "proper" ones doesn't exist:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            Intent upIntent = new Intent(this, MainActivity.class);
            if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
                NavUtils.navigateUpTo(this, upIntent);
                finish();
            } else {
                finish();
            }
            return true;
        default: return super.onOptionsItemSelected(item);
    }
}
user123321
  • 12,593
  • 11
  • 52
  • 63
  • 2
    closely related to http://stackoverflow.com/questions/12276027/how-can-i-return-to-a-parent-activity-correctly – antonv Aug 15 '13 at 20:13

6 Answers6

93

Add the following to your parent activity in the manifest file

android:launchMode="singleTop"

regarding to this answer

Community
  • 1
  • 1
Carmen
  • 6,177
  • 1
  • 35
  • 40
62

The reason, the activities are recreated when using up-navigation is, that android uses standard launch mode for this, if you do not specify an other mode. That means

"The system always creates a new instance of the activity in the target task"

and thus the activity is recreated (see docu here).

A solution would be to either declare the launch mode of the MainActivity as

android:launchMode="singleTop"

in the AndroidManifest.xml
(should always work together with Intent.FLAG_ACTIVITY_CLEAR_TOP)

or you could add FLAG_ACTIVITY_SINGLE_TOP to your intent flags, to tell the activity, that it should not be recreated, if it is on the back stack, e.g.

Intent h = NavUtils.getParentActivityIntent(this); 
h.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); 
NavUtils.navigateUpTo(this, h);
yonojoy
  • 5,486
  • 1
  • 31
  • 60
  • The part of the documentation you linked to that explained my issue was "If the parent activity has launch mode 'standard' (and the up intent does not contain FLAG_ACTIVITY_CLEAR_TOP), the current activity and its parent are both popped off the stack, and a new instance of the parent activity is created to receive the navigation intent." Thank you! – Daniel Mar 04 '22 at 07:30
12

This code worked for me:

Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
    // This activity is NOT part of this app's task, so create a new task
    // when navigating up, with a synthesized back stack.
    TaskStackBuilder.create(this)
        // Add all of this activity's parents to the back stack
        .addNextIntentWithParentStack(upIntent)
        // Navigate up to the closest parent
        .startActivities();
} else {
    // This activity is part of this app's task, so simply
    // navigate up to the logical parent activity.
    upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    NavUtils.navigateUpTo(this, upIntent);
}

return true;

No finish() invocation required.

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
Victor Denisov
  • 717
  • 5
  • 13
  • Thanks! this did solve my problem but i'm still wondering why is this happening as i did not call finish() on parent activity.. –  Sep 30 '13 at 19:18
  • 4
    May be your main activity doesn't have this option android:launchMode="singleTop" in AndroidManifest.xml. Sometimes android creates new activity even if it has already one on top. – Victor Denisov Oct 01 '13 at 07:11
  • Setting `android:parentActivityName`, using the default Up action or `NavUtils.navigateUpFromSameTask(this);` and using `intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)` for some activities made it work for me. Thanks @VictorDenisov. – FMCorz Oct 13 '13 at 07:40
  • When I add this line upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); it worked. – kml_ckr Nov 12 '13 at 09:12
  • 1
    I just tested the accepted answer with Gingerbread and unfortunately it doesn't work. – AlexBrand Dec 16 '13 at 17:59
  • @alexBrand you have to set the `android.support.PARENT_ACTIVITY` meta-data in your manifest to make it work with API level < 16. – Micky Aug 26 '14 at 10:08
4

Beginning in Android 4.1 (API level 16), you can declare the logical parent of each activity by specifying the android:parentActivityName attribute in the element. If your app supports Android 4.0 and lower, include the Support Library with your app and add a element inside the . Then specify the parent activity as the value for android.support.PARENT_ACTIVITY, matching the android:parentActivityName attribute.

<application ... >
...
<!-- The main/home activity (it has no parent activity) -->
<activity
    android:name="com.example.myfirstapp.MainActivity" ...>
    ...
</activity>
<!-- A child of the main activity -->
<activity
    android:name="com.example.myfirstapp.DisplayMessageActivity"
    android:label="@string/title_activity_display_message"
    android:parentActivityName="com.example.myfirstapp.MainActivity" >
    <!-- Parent activity meta-data to support 4.0 and lower -->
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value="com.example.myfirstapp.MainActivity" />
</activity>

If the parent activity has launch mode , or the up intent contains FLAG_ACTIVITY_CLEAR_TOP, the parent activity is brought to the top of the stack, and receives the intent through its onNewIntent() method.

<activity
        android:launchMode="singleTop"
        android:name="com.example.myfirstapp.MainActivity">

    </activity>

In Above Code "SingleTop" ,a new instance of a "singleTop" activity may also be created to handle a new intent. However, if the target task already has an existing instance of the activity at the top of its stack, that instance will receive the new intent (in an onNewIntent() call); a new instance is not created.

For Detail Documentation Click Here

To navigate up when the user presses the app icon, you can use the NavUtils class's static method, navigateUpFromSameTask(). For That Read The Documentaion given in the Link Above.

katwal-Dipak
  • 3,523
  • 2
  • 23
  • 23
1

What works for me (and I also think the cleanest) is to reorder the activity to front. If it doesn't exist on the stack it will be created as you 'nav up'.

Intent upIntent = NavUtils.getParentActivityIntent(this);
upIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(upIntent);
finish();
return true;
David
  • 5,203
  • 2
  • 16
  • 17
1

you just need to go back , not to create the activity again.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            super.onBackPressed();
            return true;
    }
    return super.onOptionsItemSelected(item);
}
Moaz Rashad
  • 1,035
  • 1
  • 10
  • 16
  • 6
    But this is wrong. See the http://developer.android.com/training/design-navigation/ancestral-temporal.html docu for that. The UP-Navigation should *always* goes to the "UP-Activity". If you, for example, start the activity from another app and the user press to up they should go to the parent. With your implementation the user goes back to the old app. – StefMa Sep 29 '15 at 09:42