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.
Related
Suppose I have a Fragment A. It has an instance variable mViewPager that points to its ViewPager.
In the onCreate(Bundle) of Fragment A, I invoke setRetainInstance(true).
Upon orientation change:
onCreateView(LayoutInflater, ViewGroup, Bundle) is called, and a new view is inflated. So, I have a new ViewPager inside the newly inflated view.
mViewPager points to the original ViewPager upon orientation change.
My question is: how do I get the new ViewPager in (1) to be associated with the retained mViewPager in (2)?
Or should I just use onSaveInstanceState(Bundle)?
As mentioned in #Selvin's comment, you should let the UI element to be recreated.
Some information which you should know:
setRetainInstance(true) should be used for non-UI Fragment only. And my personal advice would be not to consider this first, unless you are run out of option.
To properly handle a restart, it is important that your activity
restores its previous state through the normal Activity lifecycle, in
which Android calls onSaveInstanceState() before it destroys your
activity so that you can save data about the application state. You
can then restore the state during onCreate() or
onRestoreInstanceState().
You are right about using onSaveInstanceState(Bundle), in general, you should use to save your state. Please be noted that, it is the state you save, but not the UI or the whole Fragment.
For example, a state can be a count on how many times a button is clicked.
Check the link below on how to save state
http://developer.android.com/training/basics/activity-lifecycle/recreating.html#SaveState
Moreover, some UI states, e.g. text inputted in EditText are already handled in the system API. So you only need to handle states you maintained by yourself.
Edit:
If you are new to this, and do not know what you need to save and what do not, simply skip it first, and play around orientation change WITHOUT onSaveInstanceState. Then you would soon find out what is lost in the process, and that would be the state which you need to keep.
I would like to know if there is a method to Save a Custom Class while rotating in an Android app.
I want to save all instanced object called of the MatrixGame class...someone can help me?
Thanks
Since the Fragment lifecycle is independent - when you're using a Fragment you can set it so it doesn't get destroyed upon configuration changes.
As you noticed, the Activity class gets destroyed and re-created when you rotate the app (or apply other configuration changes), if you want to persist the Activity state you can use sqlite and save whatever you need in the onPause() method. Then in the onCreate() method check the DB for last known state.
If you want to avoid saving the state "forever" (meaning, the user turns off the app and tomorrow when she turns it back on - you want to start fresh and not load the last known state) you can add a timestamp and set a threshold which, if passed, the data is considered stale and gets disregarded.
Two comments:
As #saprvade wrote, Fragments gets destroyed by default, in order to prevent it you should call: setRetainInstance(true)
In case you want to implement #saprvade's other suggestion (have the activity ignore rotation changes) you can see the following explanation of how to implement: https://stackoverflow.com/a/456918/1057429
You should serialize your object. You can implement Parcelable or implement Serializable (Parcelable is several times faster). Then you will be able to put it in a Bundle in onSaveInstanceState and restore it in onCreate or onRestoreInstanceState.
Also, you can serialize your object to String, e.g. json string.
Another option would be to store your object in a database or a file. It depends on your needs.
If you don't want to recreate this object on screen rotation you can change the lifecycle of your Activity by adding a configuration change flag in AndroidManifest.xml. If we are talking about a Fragment, you can call setRetainInstance(true) to avoid fragment recreation on rotation.
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.
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.)
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.