366

Starting with the documentation:

public void setRetainInstance (boolean retain)

Control whether a fragment instance is retained across Activity re-creation (such as from a configuration change). This can only be used with fragments not in the back stack. If set, the fragment lifecycle will be slightly different when an activity is recreated:

  • onDestroy() will not be called (but onDetach() still will be, because the fragment is being detached from its current activity).
  • onCreate(Bundle) will not be called since the fragment is not being re-created.
  • onAttach(Activity) and onActivityCreated(Bundle) will still be called.

I have some questions:

  • Does the fragment also retain its view, or will this be recreated on configuration change? What exactly does "retained" mean?

  • Will the fragment be destroyed when the user leaves the activity?

  • Why doesn't it work with fragments on the back stack?

  • Which are the use cases where it makes sense to use this method?

Community
  • 1
  • 1
User
  • 31,811
  • 40
  • 131
  • 232
  • 5
    similar question with good info: [Why use Fragment#setRetainInstance(boolean)?](http://stackoverflow.com/questions/11160412/why-use-fragmentsetretaininstanceboolean) – Richard Le Mesurier Oct 11 '12 at 10:09
  • 1
    Multi-window (API 24)? Nothing you read here can be relied upon. I am seeing `Fragment.onDestroy()` **intermittently** called with corresponding nullification of fields within the Fragment supposedly protected by `setRetainInstance(true)` – Bad Loser Dec 01 '20 at 22:31

5 Answers5

367

First of all, check out my post on retained Fragments. It might help.

Now to answer your questions:

Does the fragment also retain its view state, or will this be recreated on configuration change - what exactly is "retained"?

Yes, the Fragment's state will be retained across the configuration change. Specifically, "retained" means that the fragment will not be destroyed on configuration changes. That is, the Fragment will be retained even if the configuration change causes the underlying Activity to be destroyed.

Will the fragment be destroyed when the user leaves the activity?

Just like Activitys, Fragments may be destroyed by the system when memory resources are low. Whether you have your fragments retain their instance state across configuration changes will have no effect on whether or not the system will destroy the Fragments once you leave the Activity. If you leave the Activity (i.e. by pressing the home button), the Fragments may or may not be destroyed. If you leave the Activity by pressing the back button (thus, calling finish() and effectively destroying the Activity), all of the Activitys attached Fragments will also be destroyed.

Why doesn't it work with fragments on the back stack?

There are probably multiple reasons why it's not supported, but the most obvious reason to me is that the Activity holds a reference to the FragmentManager, and the FragmentManager manages the backstack. That is, no matter if you choose to retain your Fragments or not, the Activity (and thus the FragmentManager's backstack) will be destroyed on a configuration change. Another reason why it might not work is because things might get tricky if both retained fragments and non-retained fragments were allowed to exist on the same backstack.

Which are the use cases where it makes sense to use this method?

Retained fragments can be quite useful for propagating state information — especially thread management — across activity instances. For example, a fragment can serve as a host for an instance of Thread or AsyncTask, managing its operation. See my blog post on this topic for more information.

In general, I would treat it similarly to using onConfigurationChanged with an Activity... don't use it as a bandaid just because you are too lazy to implement/handle an orientation change correctly. Only use it when you need to.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
  • Thanks a lot for your explanation, I'll review it with time :) – User Jul 09 '12 at 11:40
  • 43
    View objects are not retained, they are always destroyed on configuration changes. – Markus Junginger Jul 26 '12 at 21:29
  • @greenrobot Even within fragments? (either way, I meant "state"... not "`View`"). – Alex Lockwood Jul 27 '12 at 01:17
  • 108
    As far as I can tell, if you have `setRetainInstance(true)`, the `Fragment` java object, and all its contents are *not* destroyed on rotation, but the view *is* recreated. That is `onCreatedView()` is called again. It's basically the way it should have worked with `Activities` since Android 1.0. I don't think it is "lazy" to use it, or using it isn't "proper". In fact I can't see why it isn't the default, or why you would ever want it off. – Timmmm Sep 19 '12 at 10:18
  • 27
    I find your explanation for "Why doesn't it work with fragments on the back stack?" difficult to understand. But maybe I'm dumb :( – HGPB Oct 19 '12 at 18:41
  • @AlexLockwood Could you explain why it's not ok to use it to manage the orientation change? I've tested both ways and it seems to do everything for you without the complexity. I can't see why. – clauziere Oct 24 '12 at 21:26
  • @AlexLockwood Can you please help me with this ? http://stackoverflow.com/questions/17161159/class-members-in-fragment-become-null-after-home-button-press-and-wait – Viktor Apoyan Jun 18 '13 at 07:08
  • @AlexLockwood you mention that "it might also make sense to have the fragment retain its state if your Fragment's layout is expensive to inflate/create and you don't want it to have to be created every time the user changes the orientation of the device." Is it not the case this will cause a memory leak of the Activity Context? Your (retained) View will keep a reference to the original Activity preventing it from being garbage collected. Sure, you can give it an Application Context, but that doesn't sound practical to me. Are you able to shed any light on this situation? – Sam Hogarth Jun 28 '13 at 08:49
  • 1
    @SamHogarth Yeah, you're right. I guess I must have missed that when I first wrote that post. You would only be able to do that if both your Activity and your Fragment are being retained. You usually don't want to retain UI fragments for this reason... I've edited that part out of my answer all together, thanks for bringing it to my attention. :) – Alex Lockwood Jun 28 '13 at 16:40
  • @AlexLockwood Could it be an alternative to the Application pattern to mantain state? Like acquiring a repository to insert/get data. It doesn't seem like it but since it can survive the activity... – dierre Oct 21 '13 at 12:10
  • @dierre What do you mean by the "Application pattern"? Do you mean saving state inside a subclass of `Application`? If so, I guess those are two totally different concepts (since the `Application` object exists throughout the entire application's lifetime, but retained `Fragment`s will only exist as long as their hosting `Activity`s aren't destroyed/finished. – Alex Lockwood Oct 21 '13 at 17:51
  • @AlexLockwood yes, I was referring to it. Tnx. What I didn't get was "That is, the Fragment will be retained even if the configuration change causes the underlying Activity to be destroyed." so I thought it could survive its Activity – dierre Oct 21 '13 at 18:57
  • 14
    @dierre An activity can be destroyed in many ways. For example, if you click "back", the activity will be destroyed. If you click "home", the activity will be stopped and at some time in the future could be destroyed when memory is low. Retained `Fragment`s are only retained across configuration changes, where the underlying activity to be destroyed and immediately recreated. In all other cases in which the activity is destroyed, the retained fragments will be destroyed as well. – Alex Lockwood Oct 21 '13 at 19:56
  • @AlexLockwood From http://stackoverflow.com/questions/12640316/further-understanding-setretaininstancetrue When orientation change Fragment.onDestroyView() is called and then Fragment.onCreateView() is called again once it attached to new activity. So, if the fragment hold some views and orientation change, what is the context the fragment use to recreate it views (old activity context or the new one. If it use new activity context the memory should not be leaked. – Pongpat Nov 18 '13 at 11:14
  • We just tested whether we could indeed not add retained fragments to the back stack, but it worked. We noticed too that the docs say this wasn't possible, but it appears to work in practice. Has anyone else actually tried this? – mxk Mar 03 '14 at 15:40
  • @AlexLockwood Hello i saw your posts regarding Fragments and looks like Fragments are very native to you :) Actually i'm facing a severe problem. My use case is on Top of Activity i have chained Fragments open with hide() and add() methodology + addToBackStack(). Now when my process is killed and i again open up the app. I can see my last fragment (that's OK) but also the behind fragments that i have hidded (that's really pain). Can you please help how can i cope this situation. So that user experience is preserved. Thanks – Muhammad Babar Apr 02 '14 at 13:32
  • @MuhammadBabar How does your situation involve `setRetainInstance()`? – Alex Lockwood Apr 02 '14 at 19:06
  • @AlexLockwood didn't said that! – Muhammad Babar Apr 03 '14 at 05:40
  • Just need a suggestion from you in the case. – Muhammad Babar Apr 03 '14 at 05:41
  • Although FragmentManager is recreated, but the backStack seems not, or the entities in it are added back from somewhere. – CopperCash Jul 10 '14 at 06:19
  • 2
    What annoys me is that I have to go to a Googler's blog to understand `onRetainInstance` and not the official Android documentation! – W.K.S Sep 18 '14 at 12:32
  • It's mentioned above but here's some additional info showing how retained fragments can still be re-created by the system in certain cases. 'Don't keep activities' development option, Open app, Press Home, Open the Overview list (formerly Recents) and press the app again. You'll get this: https://gist.github.com/jameswald/b091055a213ac994f274 – James Wald Jan 28 '15 at 00:01
  • 3
    @AlexLockwood can you please confirm the following: Even though `setRetainInstance(true)` is used, one still *has to* implement their own persistence (`savedInstanceState` or otherwise) to be able to handle all scenarios: e.g. "home key, rotate, back to app" recreates my fragment with constructor call, losing all state variables. I have an `AsyncTask` as member variable, that's why I want to retain, now, if I want it to work I'm forced to stop the task, save state, and resume when user comes back. So all in all, this is just a quick way to help with rotation, but otherwise useless in general. – TWiStErRob May 05 '15 at 15:58
  • 2
    You still need to override `onSaveInstanceState()` to save the application's state. `setRetainInstance(true)` only retains the fragment across configuration changes... the activity/fragment could still be destroyed for other reasons as well though (i.e. user presses home button and later the process is killed due to low memory, etc.). – Alex Lockwood May 05 '15 at 21:41
  • Another Alex Lockwood gem :) – Sam Jun 03 '15 at 14:28
  • I wonder why we should use setRetainInstance(true) on a fragment when a default behaviour af any fragment (that is not added to back stack?) is exactly the same? "When a config change occurs the old Fragment isn't destroyed -- it adds itself back to the Activity when it's recreated. This is a massive pain in the rear most of the time" http://stackoverflow.com/questions/8474104/android-fragment-lifecycle-over-orientation-changes – Kurovsky Oct 11 '15 at 14:11
  • Tried but not getting the expected outcome about the third question. – CrazyOrr Apr 12 '16 at 13:21
  • 1
    @southerton: The wording of that answer was wrong: see it's comments. It's now been edited to remove the words "isn't destroyed". When setRetainInstance is false, what is added back to the new activity is a new fragment which is created from the old fragment's saved state. – mhsmith Feb 06 '18 at 18:46
  • I was reading about ViewModels and how it survives configuration change which led me to setRetainInstance(true) and NonConfigurationInstances. @Timmmm suggested here why setRetainInstance(true) is not default in 2012. I think ViewModel idea is pretty much the same. – Madhan Oct 13 '20 at 03:09
28

setRetaininstance is only useful when your activity is destroyed and recreated due to a configuration change because the instances are saved during a call to onRetainNonConfigurationInstance. That is, if you rotate the device, the retained fragments will remain there(they're not destroyed and recreated.) but when the runtime kills the activity to reclaim resources, nothing is left. When you press back button and exit the activity, everything is destroyed.

Usually I use this function to saved orientation changing Time.Say I have download a bunch of Bitmaps from server and each one is 1MB, when the user accidentally rotate his device, I certainly don't want to do all the download work again.So I create a Fragment holding my bitmaps and add it to the manager and call setRetainInstance,all the Bitmaps are still there even if the screen orientation changes.

suitianshi
  • 3,300
  • 1
  • 17
  • 34
  • Do you create "Data-Only" fragments (without any widget) just as a holder for you bitmaps or can those fragments have widgets as well? I've read something about the danger of producing memory leaks when the fragment contains something related to context/Activity... – hgoebl Dec 23 '15 at 11:55
  • The framework will clear the `mActivity` reference for you . But I don't know if the runtime would also clear widgets in the fragment instance in this case. Please try it out or dive into the source code. – suitianshi Dec 24 '15 at 02:23
  • Nice example of when we can use the setRetaininstance – Mu Sa Apr 19 '16 at 08:52
13

SetRetainInstance(true) allows the fragment sort of survive. Its members will be retained during configuration change like rotation. But it still may be killed when the activity is killed in the background. If the containing activity in the background is killed by the system, it's instanceState should be saved by the system you handled onSaveInstanceState properly. In another word the onSaveInstanceState will always be called. Though onCreateView won't be called if SetRetainInstance is true and fragment/activity is not killed yet, it still will be called if it's killed and being tried to be brought back.

Here are some analysis of the android activity/fragment hope it helps. http://ideaventure.blogspot.com.au/2014/01/android-activityfragment-life-cycle.html

Kejun Xia
  • 177
  • 2
  • 3
  • 8
    I'm definitely seeing onCreateView being called again on the retained fragment when rotating the screen. – aij Feb 23 '15 at 16:01
  • Is this link your own blog? You should make that clear if that's the case. – Flexo Jul 01 '15 at 07:33
13

setRetainInstance() - Deprecated

As Fragments Version 1.3.0-alpha01

The setRetainInstance() method on Fragments has been deprecated. With the introduction of ViewModels, developers have a specific API for retaining state that can be associated with Activities, Fragments, and Navigation graphs. This allows developers to use a normal, not retained Fragment and keep the specific state they want retained separate, avoiding a common source of leaks while maintaining the useful properties of a single creation and destruction of the retained state (namely, the constructor of the ViewModel and the onCleared() callback it receives).

Gastón Saillén
  • 12,319
  • 5
  • 67
  • 77
2

setRetainInstance(boolean) is useful when you want to have some component which is not tied to Activity lifecycle. This technique is used for example by rxloader to "handle Android's activity lifecyle for rxjava's Observable" (which I've found here).

Marian Paździoch
  • 8,813
  • 10
  • 58
  • 103