Since orientation changes happen fairly quickly one would think that keeping a Fragment in memory during that time would be more efficient than recreating it again.
Since it's kept for a short time only, there seem to be little impact on memory.
What then shall be good reasons NOT to use setRetainInstance(true) for each and every Fragment?
What then shall be good reasons NOT to use setRetainInstance(true) for each and every Fragment?
Google's primary concern is that you'll screw up and have data members in the fragment that refer to the old activity that you do not clean up in post-configuration lifecycle method calls (e.g., onCreateView()). For example, you might hold onto a widget in a data member, where you do not immediately null out or repopulate that data member on a configuration change. If your fragment has a reference back to the old activity, the old activity (and everything it holds onto) cannot be garbage-collected until your fragment gets destroyed. This is one of the reasons why Google does not recommend retaining any fragment with a UI.
Firstly maybe check this link: http://android-er.blogspot.com/2013/05/how-setretaininstancetrue-affect.html
Basically you shouldn't always retain the instance of the fragment because fragments are attached to activities. Hence when an activity is re-created (i.e. on configuration change), the fragment needs to be re-associated to the new activity (which leads to extra coding and some extra problems). If you just unnecessarily setRetainInstance(true), you are giving yourself more error checking and coding to do for no reason. By setting the setRetainInstance(true), you will need to deal with a different fragment lifecycle as well because certain methods in the lifecyle are now skipped (i.e. the onCreate() is no longer called after configuration changes). As far as I understand, setRetainInstance(true), won't make it more efficient because you could use onSaveInstance to save any data that you would want to use in the recreation of the same kind of fragment.
I hope this helps.
Related
I find Fragment#setRetainInstance(true) confusing. Here is the Javadoc, extracted from the Android Developer API:
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.
Question: How do you as a developer use this, and why does it make things easier?
How do you as a developer use this
Call setRetainInstance(true). I typically do that in onCreateView() or onActivityCreated(), where I use it.
and why does it make things easier?
It tends to be simpler than onRetainNonConfigurationInstance() for handling the retention of data across configuration changes (e.g., rotating the device from portrait to landscape). Non-retained fragments are destroyed and recreated on the configuration change; retained fragments are not. Hence, any data held by those retained fragments is available to the post-configuration-change activity.
It's very helpful in keeping long running resources open such as sockets. Have a UI-less fragment that holds references to bluetooth sockets and you won't have to worry about reconnecting them when the user flips the phone.
It's also handy in keeping references to resources that take a long time to load like bitmaps or server data. Load it once, keep it in a retained fragment, and when the activity is reloaded it's still there and you don't have to rebuild it.
Added this answer very late, but I thought it would make things clearer. Say after me. When setRetainInstance is:
FALSE
Fragment gets re-created on config change. NEW INSTANCE is created.
ALL lifecycle methods are called on config change, including onCreate() and onDestroy().
TRUE
Fragment does not get re-created on config change. SAME INSTANCE is used.
All lifecycle methods are called on config change, APART FROM onCreate() and onDestroy().
Retaining an instance will not work when added to the backstack.
Don't forget that the above applies to DialogFragments as well as Fragments.
The setRetainInstance(boolean) method is deprecated, use ViewModels instead.
The setRetainInstance(boolean) method on Fragments has been deprecated as of Version 1.3.0 of fragment API.
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.
This ensures that developers have a much more understandable lifecycle for those Fragments (one that matches all of the rest of their Fragments) while maintaining the useful properties of a single creation and single destruction (in this case, the constructor of the ViewModel and the onCleared() callback from the ViewModel).
I know its possible to SetRetainInstance in a fragment so that when an activity is detroyed the fragmetn isn't destroyed with it. Then when the activity is recreated we can re attached the fragment. I see lots of people using this for screen rotation, but isn't this bad practice?
Or can we ignore this?
What is the ideal way of saving info between config changes if we can't use SetRetainInstance ?
I do have one query if I did use SetRetainInstance in a fragment that means that it wouldn't get destroyed when the activity gets detroyed so how do we ensure that this activity doesn't get left behind ?
Is this a concern ?
Thanks
I know its possible to SetRetainInstance in a fragment so that when an
activity is detroyed the fragmetn isn't destroyed with it. Then when
the activity is recreated we can re attached the fragment. I see lots
of people using this for screen rotation, but isn't this bad practice?
No. What you are doing by re attaching the original fragment if it exists is avoiding creating a new instance every time the orientation changes.
Or can we ignore this?
If you do, then you will unnecessarily be creating a new instance on every rotation.
What is the ideal way of saving info between config changes if we
can't use SetRetainInstance ?
Depends on what kind on info you are trying to save. One way is to use onSavedInstanceState and onRestoreInstanceState.
I do have one query if I did use SetRetainInstance in a fragment that
means that it wouldn't get destroyed when the activity gets detroyed
so how do we ensure that this activity doesn't get left behind ?
onDetach and onDestroyView will be called in this case as well. You can clean up any views/activity references here.
I want to save the fragments state, and after referring all over, I came across two ways of doing so,
Retaining the state of fragment using setRetainInstance(true) in onCreate() method of fragment
and overriding Fragment's onSaveInstanceState(Bundle outState) method.
I tried using both and both worked for me.
I was wandering, are there any specific use cases, when to use any of them?
The major difference between overriding Fragment.onSaveInstanceState(…) and
retaining the fragment is how long the preserved data lasts. If it needs to last long enough to survive configuration changes, then retaining the fragment is much less work.
This is especially true when preserving an object, you do not have to worry about whether the object implements Serializable.
However, if you need the data to last longer, retaining the fragment is no help. If an activity is destroyed to reclaim memory after the user has been away for a while, then any retained fragments are destroyed just like they are not retained.
For an app with a small list of say quiz question,having users start over may be an acceptable choice.
But if the quiz had say 100 questions, Users would rightly be irritated at returning to the app and having to start again at the first question. You need the state of the fragment to survive for the lifetime of the activity record. To make this happen, you would use onSaveInstanceState(…).
Hope this clarifies.
The difference is how long the preserved data is retained. setRetainInstance(true) is basically useful for retaining data while a configuration change occurs (like rotation) for a very brief instant.
If the data needs to be retained while the user navigates to another app (or home screen, etc) then you should override setRetainInstance (because Android may reclaim your Activity's memory.)
I find Fragment#setRetainInstance(true) confusing. Here is the Javadoc, extracted from the Android Developer API:
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.
Question: How do you as a developer use this, and why does it make things easier?
How do you as a developer use this
Call setRetainInstance(true). I typically do that in onCreateView() or onActivityCreated(), where I use it.
and why does it make things easier?
It tends to be simpler than onRetainNonConfigurationInstance() for handling the retention of data across configuration changes (e.g., rotating the device from portrait to landscape). Non-retained fragments are destroyed and recreated on the configuration change; retained fragments are not. Hence, any data held by those retained fragments is available to the post-configuration-change activity.
It's very helpful in keeping long running resources open such as sockets. Have a UI-less fragment that holds references to bluetooth sockets and you won't have to worry about reconnecting them when the user flips the phone.
It's also handy in keeping references to resources that take a long time to load like bitmaps or server data. Load it once, keep it in a retained fragment, and when the activity is reloaded it's still there and you don't have to rebuild it.
Added this answer very late, but I thought it would make things clearer. Say after me. When setRetainInstance is:
FALSE
Fragment gets re-created on config change. NEW INSTANCE is created.
ALL lifecycle methods are called on config change, including onCreate() and onDestroy().
TRUE
Fragment does not get re-created on config change. SAME INSTANCE is used.
All lifecycle methods are called on config change, APART FROM onCreate() and onDestroy().
Retaining an instance will not work when added to the backstack.
Don't forget that the above applies to DialogFragments as well as Fragments.
The setRetainInstance(boolean) method is deprecated, use ViewModels instead.
The setRetainInstance(boolean) method on Fragments has been deprecated as of Version 1.3.0 of fragment API.
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.
This ensures that developers have a much more understandable lifecycle for those Fragments (one that matches all of the rest of their Fragments) while maintaining the useful properties of a single creation and single destruction (in this case, the constructor of the ViewModel and the onCleared() callback from the ViewModel).
Ok, I created a Fragment with some UI (couple textboxes and stuff) and I used setRetainInstance since Im running an AsyncTask to query a server (request can only be sent once) and I need the result of the AsyncTask. So my question is:
Is it wrong to retain the whole fragment with the UI? I saw couple examples where people use an extra Fragment to use the setRetainInstance but.. is there anything wrong not using that extra one??
If there is an issue with using the setRetainInstance why is that? Couldn't find any info in the documentation regarding this.
Even if you use setRetainInstance(true), your Fragment will still recreate its views when you rotate (you will get a call to onDestroyView and then onCreateView). As long as you don't keep references to views past onDestroyView, there will not be any leaks of the old Activity. The best approach would be to explicitly null the references in onDestroyView, but your code in onCreateView would generally overwrite those references anyway.
There are many examples online (including some official ones) where people use a separate fragment (without a view) to retain data. Assuming what I said above is correct, then this is unnecessary (for the sake of preventing leaks). In many cases, you may end up with cleaner code/architecture if you use a separate fragment whose responsibility is just to handle the data and not worry about the UI.
You can check to see if you are leaking Activity contexts after rotating by using Eclipse MAT.
If you are locking your orientation then you should be fine. Otherwise you can end up with memory leaks if you retain widgets that are associated with a particular activity instance.