39

I have a problem for implementing up navigation on an app with this navigation tree:

App navigation tree

The standard implementation of the back button is fine.

The problem start when trying to implement the Up button.

What I expect:

  • when the user is on Detail 5 Activity and press the up button the app goes to List 3 Activity
  • when the user is on Detail 7 Activity and press the up button the app goes back to Home Activity

So in different terms, I'd like to have this behaviour on the back stack:

app backstack clear

The Android documentation (Implementing Ancestral Navigation) advice to use the following code to handle up navigation:

Intent parentActivityIntent = new Intent(this, MyParentActivity.class);
parentActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(parentActivityIntent);
finish();

But because the parent activity of the Detail Activity differs on the different navigation path I don't know which one it really is. So I can't call it in the Intent.

Is there a way to know the real parent activity in the Android back stack?

If not, is there a way to implement a correct up navigation in this app?

ol_v_er
  • 27,094
  • 6
  • 48
  • 61

3 Answers3

22

I will stick with my comment on Paul's answer:

The idea is to have a Stack of the last Parent Activities traversed. Example:

public static Stack<Class<?>> parents = new Stack<Class<?>>();

Now in all your parent activities (the activities that are considered parents -e.g. in your case: List and Home), you add this to their onCreate:

protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     parents.push(getClass()); 
     //or better yet parents.push(getIntent()); as @jpardogo pointed
     //of course change the other codes to make use of the Intent saved.

     //... rest of your code
}

When you want to return to the Parent activity, you can use the following (according to your code):

Intent parentActivityIntent = new Intent(this, parents.pop());
parentActivityIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(parentActivityIntent);
finish();

I hope am right (:

Sherif elKhatib
  • 45,786
  • 16
  • 89
  • 106
  • I've successfully implemented your solution. It works fine. Thanks! I had to add the extras of the starting intent into the stack to restore the parent Activity with the correct intent extra but it's just an implementation detail. – ol_v_er Feb 04 '13 at 14:59
  • congratz, it is not that much of a "dirty" solution. It is actually okay – Sherif elKhatib Feb 04 '13 at 15:00
  • Yes it's not really "dirty", it works fine and it's easily unit-testable. – ol_v_er Feb 04 '13 at 15:04
  • That's a pretty clever solution. Kudos for choosing the right data structure for the job, too! Be wary that this doesn't correspond with [Android's navigation pattern](http://developer.android.com/design/patterns/navigation.html), but it *is* as the OP described. – Paul Lammertsma Feb 04 '13 at 16:07
  • Why doest-it correspond to the Android navigation pattern? I tried to implement it exactly as it should be. Where am-I wrong? – ol_v_er Feb 05 '13 at 12:41
  • I am doing the same to solve this problem, but in stead push(getClass()) on onCreate I push(getIntent()) on onPause. Otherwise there are problems with empty stack and activities not getting the correct extra data. – jpardogo Apr 01 '14 at 13:19
  • Looks solid, thanks for this. But what about **savedInstanceState**? Or **config changes** (screen orientation change) in general? In this case the parent intent will be inserted to stack multiple times. It's probably just a matter of implementation, but it's worth to consider it and have it on your mind. – Speedy Dec 30 '14 at 15:46
2

That's a tricky question and in my opinion really shows the difficulties in coping with the UX decisions of Android for the "up button". Therefore, there's not a clear-cut answer to your problem.

I have two possible solutions for you.

1. Mimicking the back button behavior.

You could consider adding an extra to the intent for launching Detail from one of its various parents. This extra would inform those activities which activity they would need to launch when android.R.id.home is pressed.

This would effectively mean that your app "goes back" to its common ancestor, instead of simply relaunching Home.

Another way of implementing this may be simply executing onBackPressed() instead of launching Home with Intent.FLAG_ACTIVITY_CLEAR_TOP, but bear in mind that the associated animation would be different than a normal "up" action.

2. Skip intermediate activites and go home.

Some apps treat the "up button" as a "home button". You might want to consider having it simply always relaunch Home with Intent.FLAG_ACTIVITY_CLEAR_TOP.

Paul Lammertsma
  • 37,593
  • 16
  • 136
  • 187
  • 1
    I never implemented this or even used this, but the app will have one of the multiple paths, and he knows which are the candidate Parents. Can't he deal with the Home button as a special backstack that contains his "Parent" activies. Code-wise: he can keep a stack of the parent activities launched and pop this stack when home is pressed. (Just Saying) – Sherif elKhatib Feb 01 '13 at 20:42
  • @SherifelKhatib It's not possible to query the backstack from the app, so I'm afraid that approach won't work. I don't think that's a big deal, because if an activity knows how it was launched, it can behave accordingly. – Paul Lammertsma Feb 01 '13 at 20:55
  • Thanks for your answer, the back implementation was my first one and it did not act exactly like I wanted. Passing in the Extra the parent was a bit tricky to do so I've implement @Sherif-elKhatib solution. The go-home up button was not the behaviour I wanted but it can be a useful way to solve the problem ;-) – ol_v_er Feb 04 '13 at 15:02
0

this is an old post for sure, but as I was studying the SharedPreferences, I think it could be a possibility to stack this information within a sharedPreferences data, and to modify its value each time before going down the 2 parents. Then by reading it, you should be able to directly know your parent, and this without having to build a whole class for that.

Alexandre
  • 1,259
  • 2
  • 15
  • 25