When OS will completely forget the state about an Activity and all information relate to an Activity ( any records about an Activity) ?
In other words when it will make Bundle to be a new instance?
I found the below explanation but it does not explain this "Killing bundle" point?
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.3_r2.1/android/app/Activity.java#Activity.onSaveInstanceState%28android.os.Bundle%29
Called to retrieve per-instance state from an activity before being killed so that the state can be restored in onCreate(android.os.Bundle) or onRestoreInstanceState(android.os.Bundle) (the android.os.Bundle populated by this method will be passed to both).
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. For example, if activity B is launched in front of activity A, and at some point activity A is killed to reclaim resources, activity A will have a chance to save the current state of its user interface via this method so that when the user returns to activity A, the state of the user interface can be restored via onCreate(android.os.Bundle) or onRestoreInstanceState(android.os.Bundle).
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(android.os.Bundle) 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(android.os.Bundle) is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState(android.os.Bundle) 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.
The default implementation takes care of most of the UI per-instance state for you by calling android.view.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(android.os.Bundle)). 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.
If called, this method will occur before onStop(). There are no guarantees about whether it will occur before or after onPause().
There are many cases where this could occur:
Here is a small topic on reference mentioning different
use-cases about recreating activities.
If you want more control over the application life cycle:
Take a look a the application object for more information.
Personal advice:
I think you should not care about when/what, This is something the
android system will manage for you, your code should be optimized to
handle all usecases (when the bundle will be null or not). A bundle
should only be used to handle state-keeping, if you want to
persist data you should take a look at fileI/O, SQLlite or shared
preference.
Related
Having a bug which relate to the os kill/restore the activity (or the app?).
After some debug find if set don't keep activities and set Background process limit to no background process will cause different behavior.
saw this post, but it does not answer the question here.
Here is what observed:
In the application it will start dagger component and it maintains some app scope singleton object, and in activity A (the default launch activity) it will by user's action to launch activity B, in B it creates and hosts a fragment. There will be some data stored in the app scope singleton object to work with the fragment.
In case of only have the don't keep activities set, when minimize the app the activities onDestroy() is called, and when re-open the app it restores the last active activity (say the user opened the activity B, the B will be re-created with the fragment restored with the savedInstanceState). In this case the app scope singleton objects managed by the dagger are still alive, so the state is completely restored to what it was before minimized the app.
But if have both don't keep activities and set Background process limit to no background process, then when minimize the app, the activity's onDestroy() is not call (only call up to the onStop()).
The behavior change is at this time if re-open the app, it will start from application onCreate(), and recreate the dagger's component. So the state before minimize the app is not re-stored.
But the os seems still remembers the last activity is B and the B's
onCreate(savedInstanceState: Bundle?)
is called with savedInstanceState having the data saved when minimizing the app, so does B's fragment.
And it is a messed up, it has data from the savedInstanceState, but the app scope singleton objects are fresh ones that do not have the data to work with the ones from the savedInstanceState.
Anyone knows in this case where is the savedInstance saved, and why although the application seems to be recreated but still the last activity (not the launching activity) is re-stored?
The savedInstanceState bundle is explicitly intended to do as you describe. Regardless of whether a background activity is destroyed to conserve memory (e.g. "don't keep activities" is turned on) or whether an entire app process is killed to conserve memory (e.g. "background process limit" is zero), the framework will provide your app the ability to save state information into the savedInstanceState bundle and will subsequently return that state information to you in future calls to onCreate().
The only situation in which savedInstanceState will be null is the very first time your activity starts up. It doesn't matter whether your app's process is killed or not; if your activity is restored you will receive a non-null savedInstanceState bundle.
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 read the below statement from android document
Because onSaveInstanceState() is not guaranteed to be called, you
should use it only to record the transient state of the activity (the
state of the UI) — you should never use it to store persistent data
Since onSaveInstanceState() is not guaranteed to be called. How can we rely on that to save data? is there any particular situation where it won't be called?
As nPn has already given the link. Read below lines
(Reference :http://developer.android.com/reference/android/app/Activity.html)
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(Bundle) 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(Bundle) is when activity B is launched in front of
activity A: the system may avoid calling onSaveInstanceState(Bundle)
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.
I would use onPause to persist object data.
See this activity life cycle diagram
http://developer.android.com/training/basics/activity-lifecycle/starting.html
Note: you should still use onSaveInstanceState() and onRestoreInstanceState(). These are your opportunity to save and restore the state of your application when for example the screen is rotated and the app is killed and then restarted.
Note: Even if the system destroys your activity while it's stopped, it still retains the state
of the View objects (such as text in an EditText) in a Bundle (a blob
of key-value pairs) and restores them if the user navigates back to
the same instance of the activity (the next lesson talks more about
using a Bundle to save other state data in case your activity is
destroyed and recreated).
the same instance of the activity
how it could be exact instance when it is destroyed and recreated , isn't it going to be a new memory block (another instance ), could anyone help me to clear this point ?
Unfortunately the documentation isn't very clear in a lot of areas. This is one of them.
In theory, if Android were to destroy your activity while it is stopped, then it would call onDestroy() and the GC would reclaim the memory. In actual fact, Android never destroys individual activities to free up memory. What it actually does is it kills the entire OS process instead. In this case, onDestroy() never gets called on any of the activities in the process. The GC doesn't bother to clean up anything, because the VM (Virtual Machine) just dies immediately along with everything else in the process and the entire amount of memory in use by the process is reclaimed by the operating system.
When your user navigates back to your application, Android creates a completely new process for your application and then it will create a new instance of your activity. In this case it will, of course, get a completely new block of memory for the instance. You will also see the constructor get called and onCreate() will also be called. However, since Android saves the state of the activity's views, that state will be restored by the activity by the call to super.onCreate().
There are a few cases where Android will destroy an instance of an activity and create a new one automatically. This is done, for example, during a configuration (ie: orientation) change. In that case, Android calls onDestroy() on the old instance and creates a new instance of the activity. The new instance gets the saved state of the old instance and can therefore restore the state of the views as able. In this case, since a new instance is being created, it will, of course, have a different address in memory.
Once a component is destroyed, it is effectively dead and the memory it is using can be reclaimed by the GC. Android will never reanimate a dead instance.
Hopefully this clarifies the situation for you.
EDIT Add more details
Android keeps track of tasks and the activities in those tasks in its own internal data structures. For each activity, it keeps a copy of the Intent that started the activity, the most recent Intent sent to that activity and it keeps a Bundle containing the saved state of that activity. Android calls onSaveInstanceState() on an activity to give the activity a chance to save anything that it will need to restore the activity if Android decides to kill it. The default implementation of onSaveInstanceState() saves the state of all the activity's views. Your implementation needs to save anything else that the activity will need to restore itself if it is killed and recreated by Android (for whatever reason). Your activity's private member variables and static variables are not automatically saved and restored in the Bundle, so if you need these to be able to recreate your activity properly you must save them yourself using the Bundle provided by onSaveInstanceState(). Static variables will stay around for the lifetime of the application's process, but since Android can kill the process (to reclaim resources) at any time, without warning, you also cannot rely on static variables always having the expected values (in the case where Android has killed and recreated your process).
If your activity (or process) is killed by Android and the user later navigates back to your activity, Android uses the information it has in its internal data structures to create a new instance of the activity. It then calls onCreate() on the new instance passing the saved instance state Bundle as a parameter. This can then be used to restore the activity to the state it had before the original instance was killed. Android will also call onRestoreInstanceState() after calling onStart() so that you can also do your restoration of state in that method if you don't want to do it in onCreate().
Note: Remember that anything you want to save/restore in a Bundle must be either a primitive (int, boolean, etc.) or it must implement Serializable or Parcelable.
The documentation of onSaveInstanceState() contains some useful information about this as well.
The state is stored, but the activity is destroyed to save memory. So, when the user is in an Activity A and goes to the Activity B, the Activity A is destroyed, but the state is stored. When the user presses the back button, the state will be loaded and everything will be restored.
The system does it when the activity call onStop and onStart. I didn't make any test, I'm just saying what I understood.
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?