web-dev-qa-db-fra.com

réutilisation de fragments dans un fragmentpageradapter

J'ai un viseur qui feuillette des fragments. Ma sous-classe FragmentPagerAdapter crée un nouveau fragment dans la méthode getItem qui semble inutile. Existe-t-il un FragmentPagerAdapter équivalent au convertView dans le listAdapter qui me permettra de réutiliser des fragments qui ont déjà été créés? Mon code est ci-dessous.

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

Le FragmentPagerAdapter met déjà en cache le Fragments pour vous. Chaque fragment se voit attribuer une balise, puis le FragmentPagerAdapter essaie d'appeler findFragmentByTag. Il appelle uniquement getItem si le résultat de findFragmentByTag est null. Vous ne devriez donc pas avoir à mettre en cache les fragments vous-même.

102
Geoff

Annexe pour le poste de Geoff:

Vous pouvez obtenir une référence à votre Fragment dans FragmentPagerAdapter en utilisant findFragmentByTag() . Le nom de la balise est généré de cette façon:

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

où viewId est l'ID de ViewPager

Regardez ce lien: http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/Android/support/v2/app/FragmentPagerAdapter.Java#104 =

67
petrnohejl

Il semble que beaucoup de personnes qui consultent cette question recherchent un moyen de référencer le Fragments créé par FragmentPagerAdapter/FragmentStatePagerAdapter. Je voudrais offrir ma solution à cela sans compter sur le en interne créé tags que les autres réponses ici utilisent.

En prime, cette méthode devrait également fonctionner avec FragmentStatePagerAdapter. Voir les notes ci-dessous pour plus de détails.


Problème avec les solutions actuelles: s'appuyer sur le code interne

Un grand nombre des solutions que j'ai vues à ce sujet et des questions similaires reposent sur l'obtention d'une référence au Fragment existant en appelant FragmentManager.findFragmentByTag() et en imitant le balise créée en interne: "Android:switcher:" + viewId + ":" + id . Le problème avec cela est que vous comptez sur le code source interne, qui, comme nous le savons tous, n'est pas garanti de rester le même pour toujours. Les ingénieurs de Android chez Google pourraient facilement décider de modifier la structure tag, ce qui casserait votre code, vous empêchant de trouver une référence au Fragments existant.

Solution alternative sans dépendre de tag interne

Voici un exemple simple de comment obtenir une référence au Fragments renvoyé par FragmentPagerAdapter qui ne dépend pas du tags interne défini sur le Fragments. La clé est de remplacer (instantiateItem() et d'enregistrer les références là-dedans à la place de dans 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();
        }
    }
}

ou si vous préférez travailler avec tags au lieu des variables des membres de la classe/références au Fragments vous pouvez également saisir tags défini par FragmentPagerAdapter de la même manière: REMARQUE: cela ne s'applique pas à FragmentStatePagerAdapter car il ne définit pas tags lors de la création de son 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;
}

Notez que cette méthode ne repose PAS sur l'imitation du tag interne défini par FragmentPagerAdapter et utilise à la place des API appropriées pour les récupérer. De cette façon, même si le tag change dans les futures versions du SupportLibrary, vous serez toujours en sécurité.


N'oubliez pas qu'en fonction de la conception de votre Activity, le Fragments sur lequel vous essayez de travailler peut ou peut ne pas exister encore, vous devez donc en tenir compte en effectuant des vérifications null avant d'utiliser vos références.

De plus, si à la place vous travaillez avec FragmentStatePagerAdapter, vous ne voulez pas conserver de références dures à votre Fragments car vous pourriez en avoir plusieurs et les références dures les garderaient inutilement en mémoire. Au lieu de cela, enregistrez les références Fragment dans les variables WeakReference au lieu des variables standard. Comme ça:

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

Si le fragment est encore en mémoire, vous pouvez le trouver avec cette fonction.

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

Exemple de code pour l'API de support v4.

17
Daniel De León

Je sais que ce n'est (théoriquement) pas une réponse à la question, mais une approche différente.

J'ai eu un problème où j'avais besoin de rafraîchir les fragments visibles. Quoi que j'aie essayé, échoué et échoué lamentablement ...

Après avoir essayé tant de choses différentes, j'ai finalement terminé cela en utilisant BroadCastReceiver. Envoyez simplement une diffusion lorsque vous avez besoin de faire quelque chose avec les fragments visibles et de la capturer dans le fragment.

Si vous avez également besoin d'une réponse, vous pouvez également l'envoyer par diffusion.

à votre santé

0
Sabo

Pour les futurs lecteurs!

Si vous songez à réutiliser des fragments avec Viewpager, la meilleure solution consiste à utiliser ViewPager 2 , car View Pager 2 utilise RecyclerView.

0
user158