I have an Activity containing some Fragments in a ViewPager. Here is the adapter (the mFooFragment‘s are members of the Activity.
private class HomePagerAdapter extends FragmentPagerAdapter
{
public HomePagerAdapter(FragmentManager fm)
{
super(fm);
}
@Override
public Fragment getItem(int position)
{
switch (position)
{
case 0:
mSellingFragment = new SellingFragment();
return mSellingFragment;
case 1:
mSearchFragment = new SearchFragment();
return mSearchFragment;
case 2:
mProfileFragment = new ProfileFragment();
return mProfileFragment;
}
return null;
}
@Override
public int getCount()
{
return 3;
}
}
And then I later do stuff like:
mSellingFragment.refresh();
Unfortunately, the member fragments can be null. One case I am ok with and can check for – the pages are lazily loaded so they are not available until they are shown. But that is ok, I only want refresh() to act on the visible page.
But sometimes they are null even when visible. I think what is happening is this:
My fragments have setRetainInstance(true) so when I navigate away from the activity it is destroyed but the fragments are retains, and then when I go back to it, the activity is recreated with the old fragments somehow, and getItem() is never called, so mFooFragment is never set.
Is that right? How exactly is one supposed to handle this? One way I can think of is adding a load of setFooFragment(FooFragment f) { mFooFragment = f; } functions to the Activity and calling them from FooFragment.onAttach() but there must be a better way!
Edit
I looked up the source code of FragmentPagerAdapter (often the only way to get answers in Android-land!) and it is indeed the case that it saves the fragments:
@Override
public Object instantiateItem(View container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), position);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + position + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), position));
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
}
return fragment;
}
Unfortunately it doesn’t make those reattached Fragments available to subclasses!
My current, slightly hacky solution is to make a copy of FragmentPagerAdapter and add a handler for when fragments are added:
void onItemCreated(Fragment fragment, int position)which you can then override in your custom pager adapter to save the fragments as member variables. Complete code below (NOT TESTED YET!)