When We can call onSaveInstanceState() to retrieve per-instance state from an activity before being killed so that the state can be restored in onCreate(Bundle) or onRestoreInstanceState(Bundle)
Why the Bundle populated by this method will be passed to both these callbacks?
Is there any specific reason behind it.
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).
-- http://developer.android.com/reference/android/app/Activity.html#onRestoreInstanceState%28android.os.Bundle%29#
onRestoreInstanceState exists for inheritance convenience.
Related
I have Fragment A with RecycleView, I'm replacing it with Fragment B using FragmentTransaction.replace(), then navigating back with popBackStack().
onDestroyView() is called, based on documentation - after onDestroyView() is called, new View will be created next time when the fragment need to be displyed.
Docs:
Called when the view previously created by {#link #onCreateView} has
been detached from the fragment. The next time the fragment needs
to be displayed, a new view will be created.
But, The RecycleView position is preserved, the position is the same when I left this Fragment.
How the RecycleView know his state if new view hierarchy in this fragment was inflated and onSaveInstanceState() wasn't called?
I believe you're trying to understand how an Android Activity "magically" saves (and restores) the transient view hierarchy when it's destroyed, without going and reading the Activity source code where this happens.
Search for onSavedInstanceState and browse the source code. Read the Javadocs.
In particular, start with void onSavedInstanceState(Bundle bundle).
You'll notice it says (and I quote):
(emphasis mine)
The default implementation takes care of most of the UI per-instance state for you by calling {#link 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
{#link #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.
Additionally, it also says that the saving instance is now always called, because sometimes it's not needed...
One example of when {#link #onPause} and {#link #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 {#link #onSaveInstanceState} on B because that particular instance will never be restored.
Which makes sense, you will never go back to Activity B (if you do, it will be a new instance with no saved state).
If you're interested in the fine details, you're going to have to clone the Android source code and/or browse it.
I don't know the exact implementation details but it's basically a serialization of a Bundle with primitive view values (the actual implementation would be in the View class since the activity calls each view to do it and stores a bundle "savedInstanceState" with all this information).
The (or one of the) hooks that trigger this behavior is in final void performSaveInstanceState(#NonNull Bundle outState) in the Activity.
The java doc is quite clear: The hook for {#link ActivityThread} to save the state of this activity..
If you look at the actual implementation, notice the call to onSaveInstanceState, and then saveManagedDialogs too, to save any dialog(s) that may be part of the hierarchy.
final void performSaveInstanceState(#NonNull Bundle outState) {
dispatchActivityPreSaveInstanceState(outState);
onSaveInstanceState(outState);
saveManagedDialogs(outState);
mActivityTransitionState.saveState(outState);
storeHasCurrentPermissionRequest(outState);
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
dispatchActivityPostSaveInstanceState(outState);
}
It also stores a bunch of interesting stuff, mActivityTransitionState and storeHasCurrentPermissionRequest. I don't know what exactly these do behind the scenes (and more importantly, how they do it), but it seems like it's somewhat implicit what they do.
If you're interested in more details you're gonna have to dig deeper yourself or hope someone with more free time explains the exact architecture of an Activity. It's an interesting exercise but not for me. It's such a big monolithic class, that I wouldn't want to venture inside of that; i mean, we're talking about a class that has over 8000 lines of code (granted, lots of comments, but still).
There's a lot of hidden complexity in an activity, lots of responsibilities, old java practices, bad and good, a unique coding style, and lots of magic happening behind the scenes by these other "objects".
Now back to your question:
How it has saved state and how it restores state, if onSaveInstanceState() not called?
The Activity calls its internal methods to save the state (in a bundle) as described in the onSaveInstanceState java docs. The class is big and there are plenty of internal/private methods that get called in the process from multiple places, so I do not know the exact architecture of how this is orchestrated (perhaps a Google engineer can try to explain, chances are nobody knows anymore at this point).
An activity will save its state provided the views have an id and it does this by calling each view#onSave... among other things; the state will be restored in onRestoreInstanceState (by the activity) if I correctly recall.
If you look at the javadocs for onRestore... (emphasis mine)
This method is called after {#link #onStart} when the activity is being re-initialized from a previously saved state, given here in savedInstanceState.
Most implementations will simply use {#link #onCreate} 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 thathad previously been frozen by {#link #onSaveInstanceState}.
This method is called between {#link #onStart} and {#link #onPostCreate}. This method is called only when recreating an activity; the method isn't invoked if {#link #onStart} is called for any other reason.
So that is how activities do it. They call onSave/onRestore internally for sure.
I found some interesting information in this other stack overflow post.
Is there technically any reason why I should use onRestoreInstanceState? Could I not do all the restoration in onCreate by checking if the savedInstanceState bundle is null? What is the primary benefit of using onRestoreInstanceState over doing everything in onCreate?
onRestoreInstanceState
This method is called after onStart() when the activity is being re-initialized from a previously saved state, given here in savedInstanceState. 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.
onRestoreInstanceState guarantees you receive a non-null Bundle object also in the lifecycle of activity it's called after onStart
But onCreate: you should always check if the Bundle object is null or not to determine the configuration change and as you know it's called before onStart
So It's all up to you and depends on your needs.
Mostly I tend to use onCreate(Bundle) to restore activity state, but if you have some initializations after which you want to restore the state its better to use onRestoreInstanceState() which offers much flexibility to restore state by the subsclasses those are extending the current activity. Also to be noted onRestoreInstanceState() is called after onStart() whereas onCreate(bundle) is called before that.
If you have huge data you can implement ViewModel class which handles the UI controller logic. ViewModel objects are automatically retained during configuration changes so that data they hold is immediately available to the next activity or fragment instance. For example, if you need to display a list of users in your app, make sure to assign responsibility to acquire and keep the list of users to a ViewModel, instead of an activity or fragment.
It also provides de-coupling and making your activity or fragment serve a single purpose rather than handling excessive responsibility of UI logic.
In my opinion, we can see this doc Restore activity UI state using saved instance state .
here are some points
1.Both the onCreate() and onRestoreInstanceState() callback methods receive the same Bundle that contains the instance state information.
2.Instead of restoring the state during onCreate() you may choose to implement onRestoreInstanceState(), which the system calls after the onStart() method. The system calls onRestoreInstanceState() only if there is a saved state to restore, so you do not need to check whether the Bundle is null:
What is the different between to reinitialize data of Activity in onCreate() and onRestoreInstanceState()
I am getting bundle in oncreate aslo.So My question is why I am not able to set data in oncreate method while the same thing is done in onRestoreInstantstate..Then what is the use of bundle object in oncreate i went through different tutorial but not got relevant answer so please if any one know the difference that where does we use the implementation to reinitialize the data of activity that whether it should be in onCreate or onRestoreInstanceState................please let me know
#numan salati Said:
onRestoreInstanceState is redundant because you can easily restore state in onCreate.
Having said that here is what the official doc says 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.
So for best practice, lay out your view hierarchy in onCreate and
restore the previous state in onRestoreInstanceState. If you do that,
anyone who subclasses your Activity can chose to override your
onRestoreInstanceState to augment or replace your restore state logic.
This is a long way of saying onRestoreInstanceState serves as a
template method.
Here
In onCreate(Bundle savedInstanceState), there`s already super.onCreate(savedInstanceState).
API says it restores states when create activity after destroyed.
But I have to override onSavedInstanceState(Bundle outState) for restore specific states.
Why?
What kind of informations are saved in savedInstanceState with method onCreate() and onSavedInstanceState()?
I'm so confused!
By default, when your device changes configuration (for example, devices rotates, you changed language settings, etc.), your foreground Activity is recreated, and all you Activity data is lost. For example, if you have a member variable mVariable that was assigned some value, after configuration change you will lose its value. That's why you need to save important data to savedInstanceState and re-init it from onCreate() method. You simply check whether savedInstanceState is not null, and if so, you init your values from savedInstance, else - init with default values.
Further reading: http://developer.android.com/training/basics/activity-lifecycle/recreating.html
onSaveInstanceState() is called before your activity is paused. So any info that it needs after it is potentially destroyed can be retrieved from the saved Bundle. The Bundle is a container for all the information you want to save. You use the put* functions to insert data into it. To get the data back out, use the get* functions just like the put* functions. The data is stored as a name-value pair. There isn't a specific use of this element, you can use it in any case (save a name, a number or whatever you need to have again when the use open again the app)
For restoring the state of the activity after it is recreated (for instance after the screen-orientation change) I implemented onSaveInstanceState() and onRestoreInstanceState(). It is simple to save/restore simple information like int, double etc. But what about saving/restoring objects like Timer?
You cannot store "live" objects (like db connections) in the Activity arguments or saved instance data. Those mechanisms are designed so that the application can be completely stopped, so it only works with things that can be "serialized" and later restored.
What you can do is use fragments. If you add a fragment without UI (check here, look for
“Adding a fragment without a UI”) and call on it setRetainInstance(true) the fragment will get reattached to the activity, surviving any configuration change.
Hope it helps. (Remember you can use fragments with old Android versions by using the support package)