This question already has answers here:
onSaveInstanceState () and onRestoreInstanceState ()
(13 answers)
Closed 9 years ago.
I have a question regarding Activity Lifecycle in Android.
I want to know, in what situation the method onRestoreInstanceState() is called ?
The documentation says
"The system calls onRestoreInstanceState() only if there is a saved
state to restore"
But I want to know when can this situation occur. Is it only applicable in case of screen rotation, when the foreground activity is destroyed and recreated ?
From the link here:
onRestoreInstanceState() is called only when recreating activity after it was killed by the OS. Such situation happen when:
orientation of the device changes (your activity is destroyed and recreated)
there is another activity in front of yours and at some point the OS kills your activity in order to free memory (for example). Next time when you start your activity onRestoreInstanceState() will be called.
In contrast: if you are in your activity and you hit Back button on the device, your activity is finish()ed (i.e. think of it as exiting desktop application) and next time you start your app it is started "fresh", i.e. without saved state because you intentionally exited it when you hit Back.
Other source of confusion is that when an app loses focus to another app onSaveInstanceState() is called but when you navigate back to your app onRestoreInstanceState() may not be called. This is the case described in the original question, i.e. if your activity was NOT killed during the period when other activity was in front onRestoreInstanceState() will NOT be called because your activity is pretty much "alive".
All in all, as stated in the documentation for onRestoreInstanceState():
Most implementations will simply use onCreate(Bundle) to restore their
state, but it is sometimes convenient to do it here after all of the
initialization has been done or to allow subclasses to decide whether
to use your default implementation. The default implementation of this
method performs a restore of any view state that had previously been
frozen by onSaveInstanceState(Bundle).
As I read it: There is no reason to override onRestoreInstanceState() unless you are subclassing Activity and it is expected that someone will subclass your subclass.
Not only that, but also:
Usually you restore your state in onCreate(). It is possible to restore it in onRestoreInstanceState() as well, but not very common. (onRestoreInstanceState() is called after onStart(), whereas onCreate() is called before onStart().
Use the put methods to store values in onSaveInstanceState():
protected void onSaveInstanceState(Bundle icicle) {
super.onSaveInstanceState(icicle);
icicle.putLong("param", value);
}
And restore the values in onCreate():
public void onCreate(Bundle icicle) {
if (icicle != null){
value = icicle.getLong("param");
}
}
You do not have to store view states, as they are stored automatically.
Related
I have three activities in my application.
From the first one i started the second, and from the second i started the third. When the process of my app is killed by the system and i launch it again i see only the last active activity is being created. And it seems the only one that gets Bundle object as a parameter to its onCreate method.
There are two things I am curious of:
If the activity at the top of the stack is the only one that gets its bundle, why each of my activities got their callback (onSaveInstanceState) called just before their onStop() method.
If only one of my activities can retain original state, what about the others? Did they lose all their state just because system decided to kill my app process? Should i restore them manually? What about views on them? (normally views get their state back without needing me to put something into the bundle and later restore if i am not mistaken)
The default behavior is this (tested on 4.1.1):
When you start a new activity, onSaveInstanceState of the previous activity is being called
When the system kills the app, the state of activities back-stack is being saved
When you restart the app, the last seen activity is being shown and its onRestoreInstanceState is being called
When you navigate back and pop activities from the back stack, state of each of them will be restored with a call to onRestoreInstanceState passing the bundle that was obtained from the first step above.
Therefore, the answers to your questions are:
All activities will be restored, but not at once - the last one seen is restored immediately, while the others will be restored when you navigate back.
All simple views (e.g. EditText) will automatically restore their state. In order for this to happen, you need to make sure that a) you did not override onSaveInstanceState or onRestoreInstanceState without call to super implementations b) the views that should be restored have unique IDs in view hierarchy
onStop is called on previous activity when you create a new activity, so you are saving the state! Your previous activity's onCreate will be called, if it's destroyed, so don't worry about recreating views. Are you sure app is killed? An app is not killed when it loses view. Android will keep it in memory as long as it doesn't need to free memory.
When orientation of screen changes, I have read many a times that in order to save data of edit text and text view or any of the radio button I have to use onSaveInstanceState() method.
But when I'm changing the screen orientation my data of edit text, text view and radio button are not getting erased.
So what is the main purpose of using onSaveInstanceState() method. Why do we have to use it if my data are preserved safely ?
Some Views/properties may be handled by default. You could go rooting through the docs to find out exactly which ones and how they are taken care of but...
I would recommend that you take manual control of these save/loads though to ensure that things are handled as you want them to be to avoid edge case bugs and also so you can then persist certain settings/properties/states if need be.
It really depends on the complexity and contents of your Activity/Fragment/Layout/View/Preference etc etc and if you even really need to remember the state things were a few moments ago.
onSaveInstanceState(Bundle outState)
This method is called before an activity may be killed so that when it comes back some time in the future it can restore its state.
Do not confuse this method with activity lifecycle callbacks such as onPause, which is always called when an activity is being placed in the background or on its way to destruction, or onStop which is called before destruction. One example of when onPause and onStop is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState on B because that particular instance will never be restored, so the system avoids calling it. An example when onPause is called and not onSaveInstanceState is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState on activity A if it isn't killed during the lifetime of B since the state of the user interface of A will stay intact.
onRestoreInstanceState(Bundle savedInstanceState)
This method is called after onStart() when the activity is being re-initialized from a previously saved state.
Most implementations will simply use onCreate(Bundle) to restore their state, but it is sometimes convenient to do it here after all of the initialization has been done or to allow subclasses to decide whether to use your default implementation. The default implementation of this method performs a restore of any view state that had previously been frozen by onSaveInstanceState(Bundle).
On the default handling of your views with this pair of methods:
The default implementation takes care of most of the UI per-instance state for you by calling View.onSaveInstanceState() on each view in the hierarchy that has an id, and by saving the id of the currently focused view (all of which is restored by the default implementation of onRestoreInstanceState). If you override this method to save additional information not captured by each individual view, you will likely want to call through to the default implementation, otherwise be prepared to save all of the state of each view yourself.
I have a viewpager holding many fragments. When the activity is sent to background and when resources are needed, the OS will kill the app or at least some fragments. When I return to the activity it crashes because the activity tries to attach new instances of all fragments it held before the clean-up and now some fields are null. This of course could be fixed by properly implementing state saving and restoring using Bundles, but I don't want to do that.
Instead I want to prevent restoring the fragments. Is there a way to tell the OS that once it has sent the GC in and destroyed fragments, it shouldn't bother recreating them at all? Once the cleaning-up happens, I want the activity to be simply recreated on return, as if a user launched it by taping the icon. Any chance of doing that?
The proposed solution here https://stackoverflow.com/a/15683289/552735 does not work. It causes exceptions
java.lang.IllegalStateException: Fragement no longer exists for key f2: index 3
I had a problem just like this. Here's how I fixed it:
#Override
protected void onSaveInstanceState(Bundle savedInstanceState)
{
savedInstanceState.clear();
}
Note that this method will ensure that absolutely no UI state information will be stored when the Activity is killed by the system - this has the effect of also not restoring any Views when onRestoreInstanceState() gets called with the same Bundle after onStart().
You can't disable the save/restore instance state actions. In case you don't want to actually implement this logic, you have to reload the form especially if your form heavily loaded with fragments.
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
startActivity(new Intent(this,YOUR_ACTIVITY.class));
finish();
}
I think my ideas on activity lifecycle and bundles
are a little confused,can you help me?
Let's suppose the user opens activity A from home screen,
activity A "calls" activity B which fills the screen.
On this event onSaveInstanceState() is called on activity A then onPause() and onStop().
Since there are too many apps currently running on the system,
andorid decides to kill the process hosting activity A.
When the user navigates back to activity A,onCreate() is called an we can
use the bundle ( setted during the last call of onSaveInstaceStae() ) to restore the state.
then onStart(),onRestoreInsanceState()
and onResume() are called,
am I right?
Then lets suppose the user presses back key to exit from activity A
onPause(),onStop() and onDestory() are called in sequence on activity A (the call of onDestroy() could be postponed though)
onSaveInsanceState() should not be called in this scenario.
When the user opens again activity A later on then the bundle
passed to onCreate() is null,right?
Now Suppose the user rotates screen
onSaveInsanceState() ,OnPause() ,OnStop(), OnDestroy() are called
then onCreate() with bundle setted by the last call to onSaveInsanceState(),
and then onStart(), and onRestore().
am I right?
My guess is that:
when the user creates an ativity,the bundle passed to onCreate() is always null and onRestoreState() is never called,but when the system creates it , for instance when it killed the activity because of low memory or because of a rotation event,the bundle passed is the one setted by the last call of onSaveInstanceState().
Is my guess right?
thanks and sorry for my poor english.
P.S. : I think onRestoreInstanceState() is passed the same bundle is passed onCreate() but typically state is restored using onCreate().
Interesting question - never thought about it.
Take a look at the documentation, onCreate() and onSaveInstanceState().
This answers at least your question what Bundle will be supplied to onCreate().
Unfortunately there is no exact definition on which events onSaveInstanceState() is called, but I guess it is called by default in all relevant situations (whatever they may be...), but you can find out for some situations (e.g. rotating the screen) by putting a Log.i() to LogCat.
onRestoreInstanceState() is passed the same bundle is passed onCreate() is right, and the system restart the activity by call onCreate() and also call onRestoreInstanceState(),the bundle will be null if get from onCreate() when the activity first started.
Since there are too many apps currently running on the system,
andorid decides to kill the process hosting activity A.
This is a very common situation. Furthermore - you can emulate this action using developers option.
In this case each activity, that was move into background, will be automatically destroyed.
About Bundle in OnCreate .
I can get from my memory only two cases when OnCreate will be called with non-null Bundle. First - described above. Second case - screen rotation.
When you launch app Android calles
onCreate
onStart
onResume
After that lets doing screen rotation. Android will call
onSaveInstanceState
onPause
onStop
onDestroy
onCreate
onStart
onRestoreInstanceState
onResume
The more information you can find on topic about recreating
I am refering to http://developer.android.com/reference/android/app/Activity.html.
I have an activity which can be "interrupted" by the user, e.g. the user opens the menu to call the preferences screen. When calling the preference screen onSaveInstanceState(Bundle) is called and I can save my data. That's fine so far. But upon pressing the back button onRestoreInstanceState(Bundle savedInstanceState) is NOT called.
So how can I save my state? Do I have to do it when calling the new activity? But how?
The only way I can think of, is saving the state by passing the state to the new activity, do nothing there with the saved data, return it to the first activity and restore the state in onActivitResult. But that would mean that I have to pass data back and forth just to restore the state. Doesn't seem to be a nice solution.
Probably a bad answer, but are you sure onRestoreInstanceState needs to be called?
The point of the bundle and onSaveInstanceState / onCreate with bundle / onRestoreInstanceState is to save transient data for an activity that is in the history stack, in case the activity must be killed to reclaim some memory. If it is killed, the activity can be restored, as if it were never killed, via onCreate / onRestonreInstanceState. However, if the activity was not killed, there may be no need to restore its transient data - presumably it is just as it was.
The Android documentation is careful to point out that onSaveInstanceStae / onRestoreInstanceState are not lifecycle methods, so aren't guaranteed to be called during lifecycle state transitions. If you need to hook into certain lifecycle transitions, take a look at the lifecycle hook methods. For example, onResume is called when the activity becomes the foreground activity and onPause is called when it is no longer the foreground activity.
Have a look at the Application Fundamentals, specifically this part:
Unlike onPause() and the other methods discussed earlier, onSaveInstanceState() and onRestoreInstanceState() are not lifecycle methods. They are not always called. For example, Android calls onSaveInstanceState() before the activity becomes vulnerable to being destroyed by the system, but does not bother calling it when the instance is actually being destroyed by a user action (such as pressing the BACK key). In that case, the user won't expect to return to the activity, so there's no reason to save its state.
Because onSaveInstanceState() is not always called, you should use it only to record the transient state of the activity, not to store persistent data. Use onPause() for that purpose instead.
Basically, any persistant data should be written out in your onPause() method and read back in onResume(). Check out the Data Storage article for ways of saving data.
Your ListView should not be cleared after returning from the Pref screen unless the Activity has been destroyed while the Pref screen was showing (in which case onCreate should have been called with the saved bundle).
The savedInstanceState is only used when the Activity has been destroyed and needs to be recreated. In this case, it looks like your ListActivity has not been destroyed.
Are you clearing your ListView manually somewhere?