Reputation: 5597
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?
Upvotes: 0
Views: 102
Reputation: 27236
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.
Upvotes: 1