19

I have two activities A and B. The A has a ListFragment which uses LoaderManager, whereas B activity shows a details about the item selected in the A's ListFragment. I've just noticed that when I use a back button to get from the B back to the A, the position in the ListFragment preserve, but when I use the up button (left-point caret) in the action bar, the A activity is recreated and thus position in list view is lost.

I would like fix this issue, but I am not sure about the best way how to do it right.

I come up with this solutions:

a) Use onBackPressed()

Replace the default implementation for the android.R.id.home (the up action bar button) in the B activity, and instead of the NavUtils.navigateUpFromSameTask(this) function call the onBackPressed() activity method. I've tested it and it works.

b) Keep use NavUtils.navigateUpFromSameTask(this)

But implement the onSaveInstanceState and restore listView position during onCreate method of the ListFragment used by the A activity. (I've not tested this approach yet)


Which of this solutions is better? Or is there any other (much more better) solution?

Solution a) is pretty simple and straight forward, but b) is probably better because the default implementation of the up caret is used.

Any ideas are welcome. Thanks.

Tomáš Mlčoch
  • 416
  • 4
  • 9

2 Answers2

10

Solution c is the correct option. First, though, an explanation of the problem with solution a.

There is absolutely no point in having two back buttons in your Activity. Furthermore, option a actually breaks the up button. The point of the up button is to provide a way for users to stay within your app when they have landed in your app from an outside source. For example, if you land on activity B from an outside activity C and if you are using your option a, then pressing "up" in activity B will result in activity C being shown. The behavior you would want would be for activity A to be shown.

As you can see, solution b is on the right track. You definitely want to go up to A and not back to C. However, simply storing the state in onSaveInstanceState will not cause the state to be retained. This is because onSaveInstanceState only gets called if your application may be killed by the system. It is not guaranteed to be called if your application was destroyed manually, and it certainly won't be called when a new instance of your Activity is created. If the Intent starts a new activity, then it will not have its state restored from the other activity.

There solution, then, is that you must write anything persistent to a shared preference file (or a custom persistent alternative). When doing this you can guarantee that all instances of an Activity share the same state across multiple tasks so long as their onResume (or wherever you restore state) is called. OR:

If you know exactly how you want your navigation to work, you can avoid writing everything to persistent state by using a combination of Intent flags and Activity task affinities. If you want to use the same activity as up even if you navigate into the application from an outside source, then you can leave your Activity A's affinity as default (linked to the application) and use something like Intent.FLAG_ACTIVITY_CLEAR_TOP.

Personally, I'd try the Intent flag approach first and failing that fall back to writing the state persistently. You just don't really want scroll location sitting on persistent storage if you can avoid it..

dcow
  • 7,765
  • 3
  • 45
  • 65
  • 12
    I've used the FLAG_ACTIVITY_CLEAR_TOP option and replace the `NavUtils.navigateUpFromSameTask(this);` with the: `Intent intent = NavUtils.getParentActivityIntent(this);` `intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);` `NavUtils.navigateUpTo(this, intent);` And it works great! Thank you. – Tomáš Mlčoch Sep 23 '13 at 19:56
  • 1
    I've also tried to change the launchMode in the manifest at the element to `android:launchMode="singleTask"` and then to `android:launchMode="singleTop"` and both were working well for my specific use case too. – Tomáš Mlčoch Sep 23 '13 at 20:01
  • @TomášMlčoch it doesn't seem like it works without the manifest changes. it keeps calling "onCreate()" even though the main activity was already created before. however, you can add Intent.FLAG_ACTIVITY_SINGLE_TOP , it works fine. here's my solution about this: http://stackoverflow.com/questions/11304483/proper-way-to-handle-action-bar-up-button – android developer Dec 05 '13 at 12:47
0

check out this presentation: https://speakerdeck.com/jgilfelt/this-way-up-implementing-effective-navigation-on-android. It answers to all of your problems.

Ciprian
  • 2,879
  • 3
  • 28
  • 28
  • 4
    Note that [link-only answers](http://meta.stackoverflow.com/tags/link-only-answers/info) are discouraged, SO answers should be the end-point of a search for a solution (vs. yet another stopover of references, which tend to get stale over time). Please consider adding a stand-alone synopsis here, keeping the link as a reference. – kleopatra Dec 12 '13 at 14:47