web-dev-qa-db-ja.com

fragmentpageradapterでフラグメントを再利用する

フラグメントをページングするビューページャーがあります。私のFragmentPagerAdapterサブクラスはgetItemメソッドで新しいフラグメントを作成しますが、これは無駄だと思われます。 FragmentPagerAdapterconvertViewと同等のlistAdapterがありますか?作成済みのフラグメントを再利用できますか?私のコードは以下です。

public class ProfilePagerAdapter extends FragmentPagerAdapter {

    ArrayList<Profile> mProfiles = new ArrayList<Profile>();

    public ProfilePagerAdapter(FragmentManager fm) {
        super(fm);
    }

    /**
     * Adding a new profile object created a new page in the pager this adapter is set to.
     * @param profile
     */
    public void addProfile(Profile profile){
        mProfiles.add(profile);
    }

    @Override
    public int getCount() {
        return mProfiles.size();
    }

    @Override
    public Fragment getItem(int position) {
        return new ProfileFragment(mProfiles.get(position));
    }
}
70
jwanga

FragmentPagerAdapterはすでにFragmentsをキャッシュしています。各フラグメントにはタグが割り当てられ、FragmentPagerAdapterfindFragmentByTagの呼び出しを試みます。 getItemからの結果がfindFragmentByTagである場合にのみ、nullを呼び出します。したがって、フラグメントを自分でキャッシュする必要はありません。

102
Geoff

Geoffの投稿の付録:

findFragmentByTag() を使用して、FragmentFragmentPagerAdapterへの参照を取得できます。タグの名前は次の方法で生成されます。

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

viewIdはViewPagerのIDです

このリンクを見てください: http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/Android/support/v2/app/FragmentPagerAdapter.Java#104 =

67
petrnohejl

この質問を見ている多くの人々が、Fragments/FragmentPagerAdapterによって作成されたFragmentStatePagerAdapterを参照する方法を探しているようです。 internally created tagsに依存せずにこれに対する私のソリューションを提供したいと思います。

ボーナスとして、このメソッドはFragmentStatePagerAdapterでも機能するはずです。詳細については、以下の注を参照してください。


現在のソリューションの問題:内部コードに依存

私がこれまで見た多くの解決策と同様の質問は、FragmentManager.findFragmentByTag()を呼び出し、 internally created tag:"Android:switcher:" + viewId + ":" + idを呼び出すことで、既存のFragmentへの参照を取得することに依存しています。 。これに関する問題は、内部ソースコードに依存していることです。これは、誰もが知っているように、永遠に同じままであるとは限りません。 GoogleのAndroidエンジニアは、既存のtagへの参照を見つけることができないコードを壊すFragments構造を変更することを簡単に決定できます。

内部tagに依存しない代替ソリューション

以下は、Fragmentsに設定された内部FragmentPagerAdapterに依存しないtagsによって返されるFragmentsへの参照を取得する方法の簡単な例です。重要なのは、 instantiateItem() をオーバーライドし、そこに参照を保存することですinstead of in getItem()

public class SomeActivity extends Activity {
    private FragmentA m1stFragment;
    private FragmentB m2ndFragment;

    // other code in your Activity...

    private class CustomPagerAdapter extends FragmentPagerAdapter {
        // other code in your custom FragmentPagerAdapter...

        public CustomPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            // Do NOT try to save references to the Fragments in getItem(),
            // because getItem() is not always called. If the Fragment
            // was already created then it will be retrieved from the FragmentManger
            // and not here (i.e. getItem() won't be called again).
            switch (position) {
                case 0:
                    return new FragmentA();
                case 1:
                    return new FragmentB();
                default:
                    // This should never happen. Always account for each position above
                    return null;
            }
        }

        // Here we can finally safely save a reference to the created
        // Fragment, no matter where it came from (either getItem() or
        // FragmentManger). Simply save the returned Fragment from
        // super.instantiateItem() into an appropriate reference depending
        // on the ViewPager position.
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
            // save the appropriate reference depending on position
            switch (position) {
                case 0:
                    m1stFragment = (FragmentA) createdFragment;
                    break;
                case 1:
                    m2ndFragment = (FragmentB) createdFragment;
                    break;
            }
            return createdFragment;
        }
    }

    public void someMethod() {
        // do work on the referenced Fragments, but first check if they
        // even exist yet, otherwise you'll get an NPE.

        if (m1stFragment != null) {
            // m1stFragment.doWork();
        }

        if (m2ndFragment != null) {
            // m2ndFragment.doSomeWorkToo();
        }
    }
}

or クラスメンバー変数/ tagsへの参照の代わりにFragmentsを使用する場合は、tagsによって設定されたFragmentPagerAdapterも同じ方法で取得できます。注:これは適用されませんFragmentStatePagerAdapterを作成するときにtagsを設定しないため、Fragmentsに。

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
    // get the tags set by FragmentPagerAdapter
    switch (position) {
        case 0:
            String firstTag = createdFragment.getTag();
            break;
        case 1:
            String secondTag = createdFragment.getTag();
            break;
    }
    // ... save the tags somewhere so you can reference them later
    return createdFragment;
}

このメソッドは、tagによって設定される内部FragmentPagerAdapterの模倣に依存せず、代わりにそれらを取得するために適切なAPIを使用することに注意してください。このようにすると、tagの将来のバージョンでSupportLibraryが変更されても、安全です。


忘れないでくださいあなたのActivityの設計に応じて、あなたがしようとしているFragmentsはまだ存在しているかもしれないし、そうでないかもしれないので、nullを実行することでそれを説明する必要があります参照を使用する前にチェックします。

また、代わりにFragmentStatePagerAdapterを使用している場合は、Fragmentsへのハード参照を保持したくない場合があります。メモリ。代わりに、標準の変数ではなくFragment変数にWeakReference参照を保存します。このような:

WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
// ...and access them like so
Fragment firstFragment = m1stFragment.get();
if (firstFragment != null) {
    // reference hasn't been cleared yet; do work...
}
23
Tony Chan

フラグメントがまだメモリ内にある場合、この関数を使用して見つけることができます。

public Fragment findFragmentByPosition(int position) {
    FragmentPagerAdapter fragmentPagerAdapter = getFragmentPagerAdapter();
    return getSupportFragmentManager().findFragmentByTag(
            "Android:switcher:" + getViewPager().getId() + ":"
                    + fragmentPagerAdapter.getItemId(position));
}

v4サポートAPIのサンプルコード

17
Daniel De León

これは(理論的には)質問に対する答えではなく、別のアプローチであることを知っています。

表示されているフラグメントを更新する必要がある問題がありました。私が試みたもの、失敗したもの、そして惨めに失敗したもの...

さまざまなことを試した後、最終的にBroadCastReceiverを使用してこれを完了しました。目に見えるフラグメントで何かをする必要があるときに、単にブロードキャストを送信して、フラグメントにキャプチャします。

何らかの応答も必要な場合は、ブロードキャストで送信することもできます。

乾杯

0
Sabo

将来の読者のために!

ビューページャーでフラグメントを再利用することを考えている場合、最良の解決策は ViewPager 2 を使用することです。これはView Pager 2がRecyclerViewを使用するためです。

0
user158