Fragment in ViewPager not restored after popBackStack
Solution 1:
After a lengthy investigation it turns out to be a problem with the fragment manager.
When using a construct like the one above the fragment transaction to reattach the fragment to the page list is silently discarded. It is basically the same problem that causes a
java.lang.IllegalStateException: Recursive entry to executePendingTransactions
when trying to alter the fragments inside the FragmentPager.
The same solution, as for problems with this error, is also applicable here. When constructing the FragmentStatePagerAdapter supply the correct child fragment manager.
Instead of
viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getFragmentManager(),mParentString));
do
viewPager.setAdapter(new SimpleFragmentStatePagerAdapter(getChildFragmentManager(),mParentString));
See also: github
Solution 2:
What Paul has failed to mention is, if you use getChildFragmentManager, then you will suffer the "blank screen on back pressed" issue.
Solution 3:
The hierarchy in my case was:
MainActivity
->MainFragment
->TabLayout
+ViewPager
->AccountsFragment
+SavingsFragment
+InvestmentsFragment
etc.
The problem I had was that I couldn't use childFragmentManager
for the reason that a click on the item Account view
(who resides inside one of the Fragment
s of the ViewPager
) needed to replace MainFragment
i.e. the entire screen.
Using MainFragment
s host Fragment
i.e. passing getFragmentManager()
enabled the replacing, BUT when popping the back-stack, I ended up with this screen:
This was apparent also by looking at the layout inspector where the ViewPager
is empty.
Apparently looking at the restored Fragment
s you would notice that their View
is restored but will not match the hierarchy of the popped state. In order to make the minimum impact and not force a re-creation of the Fragment
s I re-wrote FragmentStatePagerAdapter
with the following changes:
I copied the entire code of FragmentStatePagerAdapter
and changed
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
return f;
}
}
...
}
with
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
if (mFragments.size() > position) {
Fragment f = mFragments.get(position);
if (f != null) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
mCurTransaction.detach(f);
mCurTransaction.attach(f);
return f;
}
}
...
}
This way I am effectively making sure that that the restored Fragment
s are re-attached to the ViewPager
.