Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android onConfigurationChanged: how to save and restore fragment back stack?

I have an activity with a dual pane: a list of menu items on the left (fragment M) and details of the currently selected item on the right (fragment D).

When the user selects an item in fragment D, fragment D gets replaced with another fragment (let's call it D1). When the user selects an item in fragment D1, fragment D1 gets replaced with another fragment (let's call it D2), and so on. Of course, when the user presses the back button she can go back in the fragments history: D2->D1->D.

My problem is: how can I save and restore the full fragment back stack upon configuration change (in particular, upon screen orientation)?

It seems very strange to me that no one else had had this problem before, but I did not find anything about this during my searches on Google and Stack Overflow. If I missed any relevant post, please address me to it.

I know that I could simply add the android:configChanges="orientation|screenSize" attribute to my activity to avoid activity recreation, but I simply cannot do that.

The reason I cannot do that is that I am using Action Bar Sherlock (vers. 4) for backward compatibility and that component needs activity recreation to behave correctly upon configuration change, AFAIK.

If there is another way to recreate the Action Bar Sherlock component without destroying and re-creating the activity please let me know.

Thanks in advance.

like image 246
Luke Avatar asked Apr 03 '12 18:04

Luke


1 Answers

I was able to do this by caching the Fragments as I added them in my own ArrayList. Then I set up an OnBackStackChangedListener to keep track of which one was shown and pop off the ArrayList as necessary.

My purpose was a little different but the code below should be what you need for what you describe. The tags are so you can have multiple back stacks if you need. It won't compile as-is (I've clipped lots of my own code) but should give you an idea of how I did it. Additional disclaimer: I just got this working and there may be issues I haven't hit yet.

   public void replaceFragmentWithBackStackForTag(Fragment fragment, String tag)
   {
      FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
      ft.detach(visibleFragment);
      ft.add(R.id.realtabcontent, fragment, tag);
      ft.attach(fragment);
      ft.addToBackStack(null);
      manualBackStacks.get(tag).add(fragment);
      ft.commit();
      this.getSupportFragmentManager().executePendingTransactions();
   }

The code you'll want where your activity gets recreated after an orientation change:

 ArrayList<Fragment> backStack =
       new ArrayList<Fragment>(manualBackStacks.get(tag));
 popArrayListToIndex(manualBackStacks.get(tag), 0); // helper I wrote
 for (int bs = 1; bs < backStack.size(); bs++) {
    replaceFragmentWithBackStackForTag(backStack.get(bs), tag);
 }

The backstack listener:

 public void onBackStackChanged() {
    int index = getSupportFragmentManager().getBackStackEntryCount();
    ArrayList<Fragment> backStack = manualBackStacks.get(tag);
    visibleFragment = backStack.get(index);
    // Pop the last element if we've backed up.
    popArrayListToIndex(backStack, index);
 }

Hope this helps.

like image 169
Oded Avatar answered Oct 20 '22 11:10

Oded