2

I have got the following problem. I am trying to preserve my layout of one of my fragments on configuration change. Therefore I thought, I would be able to use setRetainInstance(true). However, it turned out not to work. The problem is, that onCreateView gets called each time on configuration change so that my layout gets reset to the initial state.

What can I do to preserve my layout? Will I have to move my code inside onCreateView somewhere else?

Please note: I cannot use the hack in the manifest with android:configChanges="orientation" since my tab hosting activity hosts more tabs. I only want to retain the state in one tab.

Here is some of my code:

public class MyFragment extends SherlockFragment {

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
        Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);   
    setRetainInstance(true);
    View rootView = inflater.inflate(R.layout.abc, container, false);

    // Some more code that was omitted ..

    return rootView;
}
}
user2426316
  • 7,131
  • 20
  • 52
  • 83
  • You should not use `setRetainInstance()` on a *visible* fragment, because if the owning activity is recreated you will leak a reference to the previous activity. – Alex MDC Aug 19 '13 at 09:58
  • @AlexMDC and what should i do to preserve my layout in visible fragments? – user2426316 Aug 19 '13 at 10:02
  • What you are describing should work automatically, even if the fragment is recreated along with the owning activity. What happens if you remove the `setRetainInstance()` call and just let the fragment revert to its default behaviour? What is incorrect about the layout when the view is restored? – Alex MDC Aug 19 '13 at 10:13
  • The problem is that a configuration change does not preserve the data that was set during runtime – user2426316 Aug 19 '13 at 10:20
  • 1
    In that case you need to persist the data yourself across the configuration change. Either use `onRetainNonConfigurationInstance()` in your activity, or use a Loader to persist the data, or use an invisible fragment (i.e. without a view) that you have called `setRetainInstance()`. A bit of plumbing is involved, but this is the Android way :) – Alex MDC Aug 19 '13 at 10:27
  • OR you can add extra data to the saved instance state bundle by implementing `onSaveInstanceState()` in your fragment. If you use this you have to flatten your data into objects that can be stored in a bundle. – Alex MDC Aug 19 '13 at 10:29
  • @AlexMDC ok, I might have to go the hacky way... – user2426316 Aug 19 '13 at 10:43
  • On the state-saving argument: do all the views from which you want to save the state have an @+id? Because (at least in an Activity) these should have their state saved automatically on application restart. Something of a free feature the guys and girls at Google seem to have implemented. Not sure if it works for Fragments though. – baske Aug 19 '13 at 10:51
  • @baske yes, they all have id's. I would be able to use `onSaveInstanceState()` but I am dealing with an async task that updates the UI. If the configuration change happens while the async task is doing its work I get the problem, that in the new orientation the newly generated UI is not set. – user2426316 Aug 19 '13 at 11:37
  • @baske in this case, I actually not just want to retain data. the async task as well – user2426316 Aug 19 '13 at 12:04
  • I think you can implement both mechanisms: 1. Create a retained fragment that hosts both your AsyncTask as well as an in-memory copy of all the data that is visualized by your app. 2. In onSaveInstanceState() persist the data in the retained fragment to flash, so that when your app is truly shut down (either because the user exits it or because the system kills it when it is in the background) your data is safe. – baske Aug 19 '13 at 15:07

1 Answers1

0

The thing you call a "hack" actually really isn't.. android:configChanges="orientation" in your manifest simply tells the Android framework that instead of the default behavior on orientation change (which is shutting down and restarting your app, causing onCreateView() in your Fragment to be called as well), you will handle orientation changes yourself, in your app.

What it does NOT do (of course) is implement your desired behavior (i.e. keeping one of your tab's layout unchanged). This you will have to do yourself, for instance by replacing all of the other layouts to a specific portrait/landscape one, but leaving the specific tab untouched. You implement this behavior in the onConfigurationChanged() callback in your Activity, which by the way will only get called once you set android:configChanges in your manifest.

baske
  • 1,316
  • 9
  • 16
  • have you read this post http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html? he describes it as kind of hacky – user2426316 Aug 19 '13 at 09:58
  • In the post you link to it is described as hacky because in that case you use the configchanges manifest attribute to prevent application destroy/create cycle for maintaining some generic application state. configchanges attribute should only be used for the situations for which is was designed, which is changes to attributes described in http://developer.android.com/reference/android/R.attr.html#configChanges. This includes changes to screen orientation. – baske Aug 19 '13 at 10:42
  • From the comments you got to your original question: please note that your question asks for a way to retain your LAYOUT. It does not mention anything about retaining form data, which judging from your comments is your actual goal. In that case I would say: make sure you implement onSaveInstanceState() correctly and reload your data when your app is re-initialized, like Alex also states in his comment. Retaining a layout is sometimes beneficial from performance point of view, but has nothing to do with correctly handling persistence of data! – baske Aug 19 '13 at 10:56