36

From my observation from Gmail and TED app the behavior of up navigation it will navigate to parent with the same state (scroll position) not like what Google say in their doc Implement Up Navigation which like create a parent intent and start it.

I implement the code from Android sample code and all state are gone (All Extra parameters I have previously set and scroll position). What is the proper way on this ? I can't find any on Android document.

Below is the code:

public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
    case android.R.id.home:
        Intent upIntent = new Intent(this, MyParentActivity.class);
        if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
            // This activity is not part of the application's task, so create a new task
            // with a synthesized back stack.
            TaskStackBuilder.from(this)
                    .addNextIntent(new Intent(this, MyGreatGrandParentActivity.class))
                    .addNextIntent(new Intent(this, MyGrandParentActivity.class))
                    .addNextIntent(upIntent)
                    .startActivities();
            finish();
        } else {
            // This activity is part of the application's task, so simply
            // navigate up to the hierarchical parent activity.
            NavUtils.navigateUpTo(this, upIntent);
        }
        return true;
}
return super.onOptionsItemSelected(item);

}

In my case I got 3 activities say A B and C, when user navigate from A to B I put some extras and onCreate of B I use that extras to query data from database to populate my rows and when I navigate back from C all extras are gone and Activity B show nothing.

Agustí Sánchez
  • 10,455
  • 2
  • 34
  • 25
sarunw
  • 8,036
  • 11
  • 48
  • 84
  • A hacky solution could be calling `finish()` in C. That would take you back to B with the previous state but you may have to requery the database in `onRestart` if you 're using `Cursor` – Peter Chaula Nov 16 '16 at 16:47

5 Answers5

92

The "standard" behaviour for an android activity is, that a new instance of the activity is created, every time there is a new intent for this activity (see launchMode-docu here). Because of this your extras seem to be gone, if you call navigateUpTo.

In your case, I would advise to use

android:launchMode="singleTop"

for your parent activity in your AndroidManifest.xml. This way you will return to your existing activity (as long as it is on the top of the back stack of your task). This way your extras will be preserved.

I too, do not understand why this is not mentioned in the Google doc you cite, as this seems the behaviour one expects if using up-navigation.

yonojoy
  • 5,486
  • 1
  • 31
  • 60
  • 7
    To clarify: add the singleTop launchMode attribute for the "parent" activity (the one being navigated up to). – Bill B Dec 30 '13 at 17:22
  • 5
    It's really frustrating that Google doesn't address this issue in the documentation: there's a very large number of StackOverflow questions about the default up-navigation behavior. Thanks for posting this! (Also, while searching through SO, I found [a useful presentation](https://speakerdeck.com/jgilfelt/this-way-up-implementing-effective-navigation-on-android) that deals with handling some more complex cases.) – gengkev Nov 18 '14 at 03:21
12

This is an alternative solution to the accepted answer:

If you cannot change the launchMode of your activity or if the parent activity is not on top of the back stack (e.g. A is parent of C), you cannot use the solution above. In this case you have to extend your navigateUpTo call to tell the activity, that it should not be recreated, if it is on the back stack:

Intent intent = NavUtils.getParentActivityIntent(this); 
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); 
NavUtils.navigateUpTo(this, intent);
Community
  • 1
  • 1
yonojoy
  • 5,486
  • 1
  • 31
  • 60
  • 2
    What's really weird is, that according to documentation of `navigateUpTo (Activity sourceActivity, Intent upIntent)`, `Navigate from sourceActivity to the activity specified by upIntent, finishing sourceActivity in the process. upIntent will have the flag FLAG_ACTIVITY_CLEAR_TOP set by this method, along with any others required for proper up navigation as outlined in the Android Design Guide.` – kpsfoo Apr 16 '14 at 17:52
  • the flag that matters, however, is FLAG_ACTIVITY_SINGLE_TOP, which isn't set by default; and that's equivalent to what the accepted answer does – gengkev Nov 18 '14 at 03:08
  • 1
    @kpsfoo the docs are stupidly misleading. If your device is running API 16+ the `NavUtils` class will simply call the newer native APIs. If you look at the source code for `Activity.navigateUpTo()` you'll see it never sets the `Intent.FLAG_ACTIVITY_CLEAR_TOP` flag. **So you simply can't rely on the support library's `NavUtils` class to behave consistently here.** That is why you must explicitly set both flags as shown in the answer. Also `FLAG_ACTIVITY_SINGLE_TOP` must be set despite what the [docs imply](http://developer.android.com/training/implementing-navigation/ancestral.html#NavigateUp). – Tony Chan Jan 20 '15 at 02:27
1

I had a similar issue when I called startActivityForResult() in my main activity with fragments and then tried to return to it from the callee using Up navigation. Solved by implementing Up navigation as:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            setResult(RESULT_CANCELED);
            finish();
            return true;
    }
    return super.onOptionsItemSelected(item);
}

In this case Up button behaves like an ordinary Back button and all states are preserved.

Alexander Zhak
  • 9,140
  • 4
  • 46
  • 72
  • finish() turns the up button into a back button, which [is not necessarily correct](http://developer.android.com/training/design-navigation/ancestral-temporal.html) – gengkev Nov 18 '14 at 03:12
1

you can use this :

@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
  • 2
    This is a bad idea: the Back button is back, the Up button is Up. They are intentionally not the same thing, with different expectations. – dsh Nov 25 '15 at 21:43
  • If you arrived at this activity from say an external link then pressing the back button won't send you to the location you expect. Also if someone puts your app into the background, using other apps, then comes back to your app the back button will go outside of your app. This is why the UP nav was introduced. You're not going BACK you're navigating within your app using a new intent hence a new instance of your activity. This is also why it creates a new activity than merely resuming what's on the stack. – chubbsondubs Mar 17 '16 at 15:19
0

You would need to save the state on the parent activity and recover it after returning from the calling one.

See Saving Android Activity state using Save Instance State for a complete explanation of the preocess, with code.

Community
  • 1
  • 1
rgrocha
  • 1,461
  • 10
  • 19
  • I have populate my Activity from database in `onCreate`, but that happen before `onRestoreInstanceState`. Should I move populate task into `onStart` ? – sarunw Nov 08 '12 at 17:33
  • 1
    After read some posts around here I believe this isn't a right way because all saved state are save and restore in case OS kill it, but in this case it like a new intent created from child activity. – sarunw Nov 08 '12 at 17:51