réutiliser des fragments dans un fragmentpageradapter

j'ai un viewpager qui page à travers des fragments. Ma sous-classe FragmentPagerAdapter crée un nouveau fragment dans la méthode getItem qui semble inutile. Y a-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 en 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));
    }
}
66
demandé sur Nisse Engström 2011-08-08 01:50:50

5 réponses

le FragmentPagerAdapter cache déjà le Fragments pour vous. Chaque fragment reçoit une étiquette, puis le FragmentPagerAdapter essaie d'appeler findFragmentByTag . Il n'appelle getItem que si le résultat de findFragmentByTag est null . Donc vous ne devriez pas avoir à cacher les fragments vous-même.

96
répondu Geoff 2016-10-13 11:19:36

Annexe pour Geoff post:

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 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
répondu petrnohejl 2014-12-28 00:52:48

semble que beaucoup de ceux qui voient cette question cherchent un moyen de faire référence au Fragments créé par FragmentPagerAdapter / FragmentStatePagerAdapter . Je voudrais offrir ma solution à cela sans compter sur le interne créé tags que les autres réponses sur l'utilisation ici.

comme bonus cette méthode devrait aussi fonctionner avec FragmentStatePagerAdapter . Voir les notes ci-dessous pour plus de détails.


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

beaucoup de solutions que j'ai vu sur cette question et des questions similaires reposent sur l'obtention d'une référence à l'existant Fragment en appelant FragmentManager.findFragmentByTag() et imitant le étiquette créée à l'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. Android les ingénieurs de Google pourraient facilement décider de changer la structure tag qui briserait votre code, vous laissant incapable de trouver une référence à l'existant Fragments .

solution Alternative sans compter sur interne tag

voici un exemple simple d'une référence au Fragments retourné par FragmentPagerAdapter qui ne s'appuie pas sur le tags interne sur le Fragments . La clé est de remplacer instantiateItem() et sauvegardez les références dans à 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 des tags à la place de membre de la classe des variables/les références à la Fragments , vous pouvez aussi saisir le tags , établi par le FragmentPagerAdapter de la même manière: NOTE: Ceci ne s'applique pas à FragmentStatePagerAdapter car il ne définit pas tags quand 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 plutôt APIs appropriés pour les extraire. De cette façon, même si le tag change dans les versions futures du SupportLibrary , vous serez toujours en sécurité.


N'oubliez pas que selon le design de votre Activity , le Fragments vous essayez de travailler sur Mai ou peut ne pas exister encore, donc vous devez tenir compte de cela en faisant null des vérifications avant d'utiliser vos références.

aussi, si à la place vous travaillez avec FragmentStatePagerAdapter , alors vous ne voulez pas garder des références dures à votre Fragments parce que vous pourriez avoir beaucoup d'entre eux et des références dures les garderaient inutilement dans la mémoire. Au lieu de sauvegarder les références Fragment dans les variables WeakReference au lieu de standard. Comme ceci:

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...
}
22
répondu Tony Chan 2015-03-26 20:27:24

si le fragment est encore dans la 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 la v4 de l'api.

17
répondu Daniel De León 2013-06-18 06:24:58

je sais qu'il ne s'agit pas (théoriquement) d'une réponse à la question, mais d'une approche différente.

j'ai eu un problème où je devais rafraîchir les fragments visibles. Quoi que j'aie essayé, j'ai échoué lamentablement...

après avoir essayé tant de choses différentes, j'ai finalement fini avec BroadCastReceiver . Il suffit d'envoyer un message lorsque vous avez besoin de faire quelque chose avec les fragments visibles et de le capturer dans le fragment.

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

cheers

0
répondu Sabo 2015-05-02 18:11:29