Android

ViewPagerからFragmentを安全に取り出す

android.support.v4.app.FragmentPagerAdapter を使うケース

このクラスは Fragment に大してタグづけを行い、FragmentManagerをデータストアとして利用し、 Fragmentのインスタンスを管理しています。
この場合、Fragmentは removeではなくdetachされたまま、FragmentManager内に残り続ける形となっています。

public APIではないですが、以下のようなタグが発行されています。

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

viewId とはコンテナとなるViewのid、ここでは ViewPagerのidです。また第二引数のidはPagerAdapterで実装したitem idであり、デフォルト実装ではポジションと等しくなっています。

したがって、 FragmentManager#findFragmentByTag(String) を用いて以下のように取り出すことが可能です。

String tag = makeFragmentName(pagerAdapter, viewPager.getId(), pagePosition);
Fragment fragment = fragmentManager.findFragmentByTag(tag);

if (fragment != null) {
    // A fragment already exists
} else {
    // :wave:
}

...
private String makeFragmentName(PagerAdapter adapter, int viewId, int position) {
    return "android:switcher:" + viewId + ":" + adapter.getItemId(position);
}

FragmentManager#instantiateItem(ViewGroup, int) を利用した方法もあるようですが、FragmentManager#findFragmentByTag(String) でヒットしなかった場合に PagerAdapter#getItem(int) が呼ばれ、(実装次第ですが)新規インスタンスが返って来ます。
加えて、それらはTransactionに追加されます。commitはされません。つまり instantiateItem を呼べば呼ぶほど新しいFragmentが作成され、追加されていきます。
PagerAdapter#finishUpdate(ViewGroup) を呼べば commit が即時実行され、Fragmentはひとまずattachだけされます。
個人的にはオススメしませんが、public apiではないkeyに頼るというのもなんとも言えないものです。

android.support.v4.app.FragmentStatePagerAdapter を使うケース

このクラスはFragmentそのものではなく、SaveStateをインメモリで管理しています。そのため一度生成したFragmentをどこかで管理するようなことはしていません。
また表示されているFragmentのインスタンスのみキャッシュされるような仕組みとなっています。
したがってこちらの方が大量のページを扱うときに向いている、メモリレスであると言われます。

さて、この場合、PagerAdapter#instantiateItem(ViewGroup, int) を用いてキャッシュされているFragmentを取り出す必要があります。

Fragment fragment = pagerAdapter.instantiateItem(viewPager, pagePosition);

if (fragment != null) {
    // A fragment already exists
} else {
    // Depends on a returned value of PagerAdapter#getItem(int)
}

が、上記のようにはなりません。
このクラスでも表示されていないFragmentはキャッシュされていないため、PagerAdapter#instantiateItem(ViewGroup, int) 内で新たに PagerAdapter#getItem(int) が呼ばれます。
SaveStateを拾って復元しようにも、そのFragmentはActiveでないため取り出すことができません。(もし可能な方法があれば教えてください)
したがって、基本的にこのAdapterでは「表示されていないFragmentに対する操作」は不可能です。
ということで、最低でも以下のように populate されているかどうかのチェックが必要です。

int currentPosition = viewPager.getCurrentItemPosition();
int offscreenPageLimit = viewPager.getOffscreenPageLimit();

if (currentPosition - offscreenPageLimit > pagePosition
        || pagePosition > currentPosition + offscreenPageLimit) {
    return;
}

Fragment fragment = pagerAdapter.instantiateItem(viewPager, pagePosition);

// A fragment is always null and already exists

雑感

Fragment怖い

@Nullable
public static Fragment getFragment(@NonNull ViewPager viewPager, @NonNull FragmentManager fragmentManager, int pagePosition) {
    PagerAdapter pagerAdapter = viewPager.getAdapter();
    if (pagerAdapter == null) return null;

    if (pagerAdapter instanceof FragmentPagerAdapter) {
        getFragment(viewPager, (FragmentPagerAdapter) pagerAdapter, fragmentManager, pagePosition);
    } else if (pagerAdapter instanceof FragmentStatePagerAdapter) {
        getFragment((FragmentStatePagerAdapter) pagerAdapter, fragmentManager, pagePosition);
    } else {
        Log.w(TAG, "Cannot support this : " + pagerAdapter.getClass().getSimpleName());
        return null;
    }
}

@Nullable
public static Fragment getFragment(@NonNull ViewPager viewPager, @NonNull FragmentPagerAdapter pagerAdapter, @NonNull FragmentManager fragmentManager, int pagePosition) {
    String tag = "android:switcher:" + viewPager.getId() + ":" + pagerAdapter.getItemId(pagePosition);
    return fragmentManager.findFragmentByTag(tag);
}

@Nullable
public static Fragment getFragment(@NonNull ViewPager viewPager, @NonNull FragmentStatePagerAdapter pagerAdapter, int pagePosition) {
    int currentPosition = viewPager.getCurrentItemPosition();
    int offscreenPageLimit = viewPager.getOffscreenPageLimit();

    if (currentPosition - offscreenPageLimit > pagePosition
            || pagePosition > currentPosition + offscreenPageLimit) {
        return null;
    }

    return pagerAdapter.instantiateItem(viewPager, pagePosition);
}