I have an activity where I am calling three fragments - each depending on each other:
A(ctivity) -> f1 (Fragment one, title {is|should}: list) -> f2 (Fragment two,
You can find a nice Fragment
lifecycle diagram in the android docs here. So yes, if the fragment is brought to the foreground from the backstack onCreateView()
, onActivityCreated()
, onStart()
and onResume()
are called.
I know this is a bit late for an answer but for anyone who navigates here this might help!
First thing is first: popBackStack()doesn't pop a fragment, it pops a fragment transaction. So the last fragment transaction is reversed upon being called. If you were displaying FragmentA currently and your transaction was:
fragmentTransaction.replace(R.id.your_layout, fragmentB);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
It would replace FragmentA with FragmentB, and add that transaction (not the fragment) to the back stack. If you then hit the back button, it pops the transaction off the back stack, which was "replace this FragmentA with a FragmentB". Essentially, this instruction reverses the last transaction and removes it from the stack of transactions carried out. If the original FragmentA still exists, it uses that one. If it's been destroyed, it makes a new one.
So, if the Fragment hasn't been destroyed, then recalling the fragment after using on popBackStack(), the onStart() and onResume() methods are called. If the Fragment has been destroyed previously, then the lifecycle methods will be called starting from onAttach(). It's the same as pressing the back button on Activities.
Now the important bit, what happens re fragment lifecycle when we pop off back stack? Well as said before the fragment transaction is reversed so:
Scenario 1: Your fragmentB didn't already exist before transaction. In this case the onCreate() and onAttach() methods are called during the transaction so the fragment will be destroyed and detached if you call popBackStack() and reverse the transaction (Note FragmentA probably already existed so replacing it wont destroy it as we're not undoing a fragment creation). In this case the lifecycle methods will be called starting from onAttach().
Scenario 2: Your fragmentB did already exist before transaction. In this case the fragment won't be destroyed and the next time you access it the onStart() and onResume() methods are called.
This fellow here explains a few things about using popbackstack() http://vinsol.com/blog/2014/09/19/transaction-backstack-and-its-management/ and the fragment lifecycle http://vinsol.com/blog/2014/10/22/fragment-view-state-retention-a-dirty-solution/. The other related posts are worth reading too!
I use following workaround:
1) set 1st fragment setHasOptionsMenu(false)
before add 2nd fragment on top of 1st one.
2) set 1st fragment setHasOptionsMenu(true)
in onOptionsItemSelected()
after return from 2nd fragment.
3) onCreateOptionsMenu()
of 1st fragment should be called and you can change actionbar here.
But I want to know a better solution.
There's also one other good source that you can read through.
I think, the important point is the difference of the transaction you performed on Fragment B. If it's add, then no lifecycle methods are called on Fragment A, if it's replace, you will get some calls on those methods.
use addOnBackStackChangedListener method in your BaseActivity, which will be called any time backstack changes
getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
FragmentManager fm = getSupportFragmentManager();
if (fm != null) {
int backStackCount = fm.getBackStackEntryCount();
if (backStackCount == 0) {
if (getSupportActionBar() != null) {
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
}
setToolbarTittle(R.string.app_name);
} else {
if (getSupportActionBar() != null) {
getSupportActionBar().setHomeAsUpIndicator(R.drawable.back);
}
}
}
}
});
My workaround is to get the current title of the actionbar in the Fragment before setting it to the new title. This way, once the Fragment is popped, I can change back to that title.
@Override
public void onResume() {
super.onResume();
// Get/Backup current title
mTitle = ((ActionBarActivity) getActivity()).getSupportActionBar()
.getTitle();
// Set new title
((ActionBarActivity) getActivity()).getSupportActionBar()
.setTitle(R.string.this_fragment_title);
}
@Override
public void onDestroy() {
// Set title back
((ActionBarActivity) getActivity()).getSupportActionBar()
.setTitle(mTitle);
super.onDestroy();
}