I've encountered some curious behavior in my application when managing Fragments and I was wondering if SO could help shed some light onto why this happens.
I have two Fragments, we'll call them Fragment A and Fragment B. The general flow of my application is that when the user interacts with Fragment A in some way, Fragment B is shown by calling fragmentTransaction.replace()
(this happens in all cases). When I show Fragment B, I add Fragment A to the back stack; then, when the user presses the back button on Fragment B, Fragment A gets shown again by popping from the back stack.
That's all well and good, but today I discovered that there is a flow from Fragment B which calls fragmentTransaction.replace()
, replacing Fragment B with the same instance of Fragment A that is currently on the back stack.
In and of itself there's nothing wrong with that, however the strange behavior arises when I go back from Fragment A into Fragment B. If I called fragmentTransaction.replace()
, the onCreate()
method of Fragment B is not called.
However, if I popped Fragment A from the back stack and then replaced it with Fragment B, the onCreate()
method of Fragment B is fired. Why is this?
Note that all instances of Fragment A and Fragment B are created at the time their host Activity is launched.
Edit for clarification. The case where onCreate()
is called a second time is the following: Attach Fragment A => replace with Fragment B, adding Fragment A to the back stack => pop Fragment A using popBackStack()
=> replace Fragment A with Fragment B again.
This is maybe because the fragment manager reuse the fragment instance rather recreate it. If the code inside Fragment B
onCreate()
requires to be executed when the fragment is shown, then move the code in another method likeonResume()
.replace()
does 2 things:These 2 operations are what is saved as a Backstack record / transaction. Note that fragment A remains in
created
state, and its view is destroyed.Now
popBackStack()
reverses your last transaction that you've added to BackStack.In this case that would be 2 steps:
After this, fragment B becomes
detached
, and if you did not keep references to it, it will be garbage collected.To answer first part of your question, there's no
onCreate()
call, because FragmentB remained increated
state. And answer to second part of the question is a bit longer.First, it is important to understand that you don't actually add
Fragments
to Backstack, you addFragmentTransactions
. So when you think that you "replace with Fragment B, adding Fragment A to the back stack", you actually add this whole operation to backstack - that is replacement of A with B. This replacement consists of 2 actions - remove A and add B.Then, next step is popping of the transaction that contains this replacement. So you're not popping FragmentA, you're reversing "remove A, add B", which reversed is "remove B, add A".
And then final step should be clearer - there's no B that FragmentManager is aware of, so when you add it by replacing A with B at your last step, B needs to go through its early lifecycle methods -
onAttach()
andonCreate()
.Code below illustrates what is happening.