The general pattern for using a FragmentPagerAdapter looks something like this…

public static class MyAdapter extends FragmentPagerAdapter {
    public MyAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    @Override
    public Fragment getItem(int position) {
        return ArrayListFragment.newInstance(position);
    }
}

The above code works perfectly, however if getItem(int) was to be called by anything other than FragmentPagerAdapter, things may get weird.

The getItem(int) method gets called by instantiateItem(ViewGroup, int) if the Fragment at the given position doesn’t exist already in the FragmentManager. This explains why getItem(int) returns a new instance every time it’s called in the snippet above.

However, since getItem(int) is a public method, it may be called by anything other than itself. As an example, lets expand on the snippet above…

public class FragmentPagerSupport extends FragmentActivity {
    static final int NUM_ITEMS = 10;

    MyAdapter mAdapter;

    ViewPager mPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_pager);

        mAdapter = new MyAdapter(getSupportFragmentManager());

        mPager = (ViewPager)findViewById(R.id.pager);
        mPager.setAdapter(mAdapter);

        // This will return a new instance and execute doSomething()
        ((CustomFragment) mAdapter.getItem(0)).doSomething();
    }

    public static class MyAdapter extends FragmentPagerAdapter {
        public MyAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public int getCount() {
            return NUM_ITEMS;
        }

        @Override
        public Fragment getItem(int position) {
            return ArrayListFragment.newInstance(position);
        }
    }
}

The above code will attach MyAdapter to the ViewPager and then try to retreive the first Fragment to execute the method doSomething(). The only problem with this is that when we try to retreive a Fragment using getItem(int), it will always return a new instance. The retreived instance will not always be the same as the one being displayed if we were to use this method, so if doSomething() were to update the UI, we probably wouldn’t see it on the screen.

To solve this problem, we could make use of the FragmentManager and simply check to see if the Fragment exists in the FragmentManager already. If so return the existing Fragment, otherwise create a new instance.

To accomplish this, we need to do a couple things first.

  1. Determine how the Fragments are being saved.
  2. Retreive Fragments using the method found in step 1.

Luckily, I’ve already went through the source code for FragmentPagerAdapter. Here’s the bit that saves the Fragment…

// 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));
}

As you can see, it’s saving/retreiving the Fragment by a unique string. This unique string is generated by makeFragmentName(int, int), which does the following:

private static String makeFragmentName(int viewId, int index) {
    return "android:switcher:" + viewId + ":" + index;
}

All we have to do is incorporate this makeFragmentName(int, int) method and use findFragmentByTag(String) and we’re done!

public static class MyAdapter extends FragmentPagerAdapter {
    private FragmentManager mFragmentManager;

    public MyAdapter(FragmentManager fm) {
        super(fm);
        mFragmentManager = fm; // Cache this so we can use it later on...
    }

    @Override
    public int getCount() {
        return NUM_ITEMS;
    }

    @Override
    public Fragment getItem(int position) {
        // Check if this Fragment already exists.
        String name = makeFragmentName(R.id.pager, position);
        Fragment f = mFragmentManager.findFragmentByTag(name);
        if(f == null)
            ArrayListFragment.newInstance(position);

        return f;
    }

    private static String makeFragmentName(int viewId, int index) {
        return "android:switcher:" + viewId + ":" + index;
    }
}