Comment obtenir des fragments existants lors de l'utilisation de FragmentPagerAdapter

99

J'ai du mal à faire en sorte que mes fragments communiquent entre eux via le Activity, qui utilise le FragmentPagerAdapter, comme classe d'assistance qui implémente la gestion des onglets et tous les détails de connexion d'un ViewPageravec associé TabHost. J'ai implémenté FragmentPagerAdapterexactement la même chose que celle fournie par l'exemple de projet Android Support4Demos .

La question principale est de savoir comment puis-je obtenir un fragment particulier à partir FragmentManagerduquel je n'ai ni identifiant ni tag? FragmentPagerAdaptercrée les fragments et génère automatiquement l'ID et les balises.

Ismar Slomic
la source
Double
jk2K
@ jk2K comment cela peut-il être le double d'une question posée 1 an après
Davi
@Dawit duplique comme une étiquette, sans rapport avec le temps, les questions ultérieures ont des vues plus élevées
jk2K
La plupart des réponses ici ne fonctionnent pas en production, alors vérifiez ma réponse dans stackoverflow.com/a/54280113/2413303
EpicPandaForce

Réponses:

194

Résumé du problème

Remarque: Dans cette réponse, je vais faire référence FragmentPagerAdapteret son code source. Mais la solution générale devrait également s'appliquer à FragmentStatePagerAdapter.

Si vous lisez ceci, vous savez probablement déjà que FragmentPagerAdapter/ FragmentStatePagerAdapterest censé créer Fragmentspour votre ViewPager, mais lors de la récréation d'activité (que ce soit à partir d'une rotation de périphérique ou du système tuant votre application pour regagner la mémoire), ceux- Fragmentsci ne seront pas créés à nouveau, mais à la place instances récupérées duFragmentManager . Dites maintenant vos Activitybesoins pour obtenir une référence à ceux-ci Fragmentspour y travailler. Vous n'avez pas créé un idou tagpour ceux-ci, Fragmentscar vous les FragmentPagerAdapter définissez en interne . Le problème est donc de savoir comment obtenir une référence à eux sans cette information ...

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

Beaucoup des solutions que je l' ai vu sur ce sujet et des questions similaires comptent sur l' obtention d' une référence à l'existant Fragmenten appelant FragmentManager.findFragmentByTag()et en imitant l' étiquette créée en interne:"android:switcher:" + viewId + ":" + id . Le problème avec cela est que vous vous fiez au code source interne, qui, comme nous le savons tous, n'est pas garanti de rester le même pour toujours. Les ingénieurs Android de Google pourraient facilement décider de changer la tagstructure qui briserait votre code vous laissant incapable de trouver une référence à l'existant Fragments.

Solution alternative sans compter sur les tag

Voici un exemple simple de la façon d'obtenir une référence au Fragmentsrenvoyé par FragmentPagerAdapterqui ne repose pas sur l' tagsensemble interne du Fragments. La clé est de remplacer instantiateItem()et d'enregistrer les références là-dedans plutôt que 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 tagsau lieu de variables / références de membres de classe, Fragmentsvous pouvez également récupérer l' tagsensemble par FragmentPagerAdapterde la même manière: REMARQUE: cela ne s'applique pas FragmentStatePagerAdaptercar il n'est pas défini tagslors 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 de l' tagensemble interne par FragmentPagerAdapteret utilise à la place des API appropriées pour les récupérer. De cette façon, même si les tagchangements dans les futures versions du, SupportLibraryvous serez toujours en sécurité.


N'oubliez pas que selon la conception de votre Activity, le sur Fragmentslequel vous essayez de travailler peut ou peut ne pas exister encore, vous devez donc en tenir compte en effectuant des nullvérifications avant d'utiliser vos références.

De plus, si au contraire vous travaillez avec FragmentStatePagerAdapter, vous ne voulez pas garder de références sérieuses à votre Fragmentscar vous pourriez en avoir beaucoup et des références difficiles les garderaient inutilement en mémoire. Au lieu de cela, enregistrez les Fragmentréférences dans des WeakReferencevariables au lieu de celles 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...
}
Tony Chan
la source
3
C'est une très bonne solution, mais elle semble perdre de son efficacité si vous ne savez pas combien de fragments seront transmis.
Riot Goes Woof
3
@Zorpix vous pouvez stocker les fragments de création dans un HashMap: map.put (position, createdFragment);
Tom Bevelander
12
Cela mérite la coche! Un moyen très intelligent et complet d'accomplir cela. Vous m'avez beaucoup aidé merci!
young_souvlaki
2
Au début, cette solution semblait trop compliquée, alors je l'ai ignorée. J'y suis finalement revenu, car les autres réponses n'étaient pas satisfaisantes. Et ce n'était pas aussi difficile que je le pensais.
Suragch
1
pas besoin de remplacer quoi que ce soit et vous ne devriez en fait pas passer outre instantiateItem. la bonne façon de le faire est d' appeler instantiateItem à la onCreateméthode de votre activité entourée startUpdateet finishUpdate. Voir ma réponse pour plus de détails
morgwai
82

J'ai trouvé une réponse à ma question sur la base du post suivant: réutilisation de fragments dans un fragmentpageradapter

Peu de choses que j'ai apprises:

  1. getItem(int position)dans le FragmentPagerAdapternom plutôt trompeur de ce que cette méthode fait réellement. Il crée de nouveaux fragments, sans renvoyer ceux existants. Dans ce sens, la méthode doit être renommée en quelque chose comme createItem(int position)dans le SDK Android. Donc, cette méthode ne nous aide pas à obtenir des fragments.
  2. Sur la base des explications fournies dans le post- support, FragmentPagerAdapter contient une référence à d'anciens fragments, vous devez laisser la création des fragments au FragmentPagerAdapteret, ce qui signifie que vous n'avez aucune référence aux fragments ou à leurs balises. Si vous avez une balise fragment, vous pouvez facilement en récupérer une référence à partir de FragmentManageren appelant findFragmentByTag(). Nous avons besoin d'un moyen de trouver la balise d'un fragment à une position de page donnée.

Solution

Ajoutez la méthode d'assistance suivante dans votre classe pour récupérer la balise de fragment et l'envoyer à la findFragmentByTag()méthode.

private String getFragmentTag(int viewPagerId, int fragmentPosition)
{
     return "android:switcher:" + viewPagerId + ":" + fragmentPosition;
}

REMARQUE! Il s'agit d'une méthode identique à celle FragmentPagerAdapterutilisée lors de la création de nouveaux fragments. Voir ce lien http://code.google.com/p/openintents/source/browse/trunk/compatibility/AndroidSupportV2/src/android/support/v2/app/FragmentPagerAdapter.java#104

Ismar Slomic
la source
Btw, il y a plus sur le sujet dans cette Q&R: stackoverflow.com/questions/6976027/...
Thomas
1
quel est le paramètre d'entrée viewId? Quelle vue?
Nilzor du
@Nilzor viewId est l'identifiant du ViewPager.
Dr.jacky
Peut-être qu'au lieu de deviner l'étiquette, le fragment pourrait raconter son étiquette à son activité onAttach()?
bassin
4
Ce n'est pas la bonne manière. La réponse de @Tony Chan est la meilleure et la bonne manière.
Morteza Rastgoo
17

vous n'avez pas besoin de remplacer instantiateItemni de vous fier à la compatibilité avec la makeFragmentNameméthode interne en créant manuellement des balises de fragment.
instantiateItemest une publique méthode afin que vous puissiez et réellement devrait l' appeler dans la onCreateméthode de votre activité entourée d'appels à startUpdateet finishUpdateprocédés décrits dans PagerAdapter javadoc :

Un appel à la méthode PagerAdapter startUpdate (ViewGroup) indique que le contenu du ViewPager est sur le point de changer. Un ou plusieurs appels à instancierItem (ViewGroup, int) et / ou destroyItem (ViewGroup, int, Object) suivront, et la fin d'une mise à jour sera signalée par un appel à finishUpdate (ViewGroup).

Vous pouvez ensuite, par le biais de ce qui précède, stocker des références aux instances de vos fragments sur des variables locales si vous en avez besoin. Voir exemple:

public class MyActivity extends AppCompatActivity {

    Fragment0 tab0; Fragment1 tab1;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.myLayout);
        ViewPager viewPager = (ViewPager) findViewById(R.id.myViewPager);
        MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(adapter);
        ((TabLayout) findViewById(R.id.tabs)).setupWithViewPager(viewPager);

        adapter.startUpdate(viewPager);
        tab0 = (Fragment0) adapter.instantiateItem(viewPager, 0);
        tab1 = (Fragment1) adapter.instantiateItem(viewPager, 1);
        adapter.finishUpdate(viewPager);
    }

    class MyPagerAdapter extends FragmentPagerAdapter {

        public MyPagerAdapter(FragmentManager manager) {super(manager);}

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

        @Override public Fragment getItem(int position) {
            if (position == 0) return new Fragment0();
            if (position == 1) return new Fragment1();
            return null;  // or throw some exception
        }

        @Override public CharSequence getPageTitle(int position) {
            if (position == 0) return getString(R.string.tab0);
            if (position == 1) return getString(R.string.tab1);
            return null;  // or throw some exception
        }
    }
}

instantiateItemessaiera d'abord d'obtenir des références à des instances de fragment existantes à partir de FragmentManager. Seulement s'ils n'existent pas encore, il en créera de nouveaux en utilisant la getItemméthode de votre adaptateur et les «stockera» dans le FragmentManagerpour toute utilisation future.

Il est important de noter que même si vous n'avez pas besoin d'obtenir des références à vos fragments, vous devez quand même appeler instantiateItemtous vos onglets entourés par startUpdate/ finishUpdatedans votre onCreateméthode comme ceci:

    adapter.startUpdate(viewPager);
    // ignoring return values of the below 2 calls, just side effects matter:
    adapter.instantiateItem(viewPager, 0);
    adapter.instantiateItem(viewPager, 1);
    adapter.finishUpdate(viewPager);

Si vous ne le faites pas, vous risquez que vos instances de fragments ne seront jamais engagés à FragmentManager: lorsque votre activité devient de premier plan instantiateItemsera automatiquement appelée pour obtenir vos fragments, mais startUpdate/ finishUpdate peuvent pas (selon les détails de mise en œuvre) et ce qu'ils essentiellement faire est de commencer / valider un FragmentTransaction.
Cela peut entraîner la perte très rapide des références aux instances de fragment créées (par exemple lorsque vous faites pivoter votre écran) et la recréation beaucoup plus souvent que nécessaire. En fonction de la «lourdeur» de vos fragments, cela peut avoir des conséquences non négligeables sur les performances.
De plus, dans ce cas, des instances de fragments stockés sur des variables locales peuventdeviennent obsolètes: si la plate-forme Android tente de les obtenir FragmentManagerpour une raison quelconque, elle échouera et en créera et en utilisera de nouvelles, tandis que vos vars référenceront toujours les anciens.

Morgwai
la source
1
Cela pourrait être la meilleure solution dans certains cas. Mais que se passera-t-il si FragmentManger tue le fragment et le recrée?
woltran
1
@woltran FragmentManagerne peut pas simplement tuer au hasard ( détruire est le mot juste ici) votre Fragment(pensez à ce qui se passerait s'il décidait de tuer un Fragmentqui est actuellement affiché;)). En général, le cycle de vie d'un Fragmentest lié à son Activity(voir github.com/xxv/android-lifecycle pour plus de détails) -> a Fragmentne peut être détruit que s'il a Activityété détruit. Dans ce cas, lorsqu'un utilisateur retourne à la donnée, Activityelle onCreatesera appelée à nouveau et une nouvelle instance de la Fragmentsera créée.
morgwai
C'est la vraie réponse
MJ Studio
Devez-vous vraiment créer des fragments plutôt que de vous fier à leur création lorsque l'utilisateur fait défiler ViewPager par exemple?
Yar
@Yar oui, tu devrais vraiment. L'extrait de documentation que j'ai fourni l'indique clairement et la section «Quelques informations supplémentaires» explique pourquoi.
morgwai
11

La façon dont je l'ai fait est de définir une table de hachage de WeakReferences comme suit:

protected Hashtable<Integer, WeakReference<Fragment>> fragmentReferences;

Ensuite, j'ai écrit la méthode getItem () comme ceci:

@Override
public Fragment getItem(int position) {

    Fragment fragment;
    switch(position) {
    case 0:
        fragment = new MyFirstFragmentClass();
        break;

    default:
        fragment = new MyOtherFragmentClass();
        break;
    }

    fragmentReferences.put(position, new WeakReference<Fragment>(fragment));

    return fragment;
}

Ensuite, vous pouvez écrire une méthode:

public Fragment getFragment(int fragmentId) {
    WeakReference<Fragment> ref = fragmentReferences.get(fragmentId);
    return ref == null ? null : ref.get();
}

Cela semble bien fonctionner et je le trouve un peu moins piraté que le

"android:switcher:" + viewId + ":" + position

astuce, car il ne dépend pas de la façon dont le FragmentPagerAdapter est implémenté. Bien sûr, si le fragment a été publié par le FragmentPagerAdapter ou s'il n'a pas encore été créé, getFragment renverra null.

Si quelqu'un trouve quelque chose qui ne va pas avec cette approche, les commentaires sont plus que bienvenus.

personne3000
la source
int fragmentIddevrait être renommé enint position
lmaooooo
7
J'utilisais une approche très similaire. Mais cela échoue lorsque le téléavertisseur est créé à partir d'un ensemble savedState. Par exemple: l'activité passe en arrière-plan et revient au premier plan après l'appel de onSavedStateInstance (). Dans ce cas, les méthodes getItem () ne seront pas appelées.
Anoop
Quelle est la raison de créer votre propre carte puisqu'il y en a déjà une dans FragmentManager qui est toujours up2date? Voir ma réponse pour plus de détails.
morgwai
De plus, le fait qu'un fragment a été détruit ne garantit pas qu'il n'y ait pas de références fortes à celui-ci (bien que ce soit probable, mais PAS garanti), auquel cas votre carte contiendrait toujours des fragments périmés.
morgwai
1
Cela ne fonctionnera pas correctement une fois que le système recrée les fragments.
EpicPandaForce
10

J'ai créé cette méthode qui fonctionne pour moi pour obtenir une référence au fragment actuel.

public static Fragment getCurrentFragment(ViewPager pager, FragmentPagerAdapter adapter) {
    try {
        Method m = adapter.getClass().getSuperclass().getDeclaredMethod("makeFragmentName", int.class, long.class);
        Field f = adapter.getClass().getSuperclass().getDeclaredField("mFragmentManager");
        f.setAccessible(true);
        FragmentManager fm = (FragmentManager) f.get(adapter);
        m.setAccessible(true);
        String tag = null;
        tag = (String) m.invoke(null, pager.getId(), (long) pager.getCurrentItem());
        return fm.findFragmentByTag(tag);
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } 
    return null;
}
Pepijn
la source
C'est bien de se souvenir d'avoir créé la méthode et le terrain en dehors de la méthode pour de meilleures performances
Marcos Vasconcelos
2

la solution suggérée par @ personne3000 est sympa, mais elle a un problème: quand l'activité passe en arrière-plan et est tuée par le système (afin d'avoir de la mémoire libre) puis restaurée, le fragmentReferencessera vide, car getItemne serait pas appelé.

La classe ci-dessous gère une telle situation:

public abstract class AbstractHolderFragmentPagerAdapter<F extends Fragment> extends FragmentPagerAdapter {

    public static final String FRAGMENT_SAVE_PREFIX = "holder";
    private final FragmentManager fragmentManager; // we need to store fragment manager ourselves, because parent's field is private and has no getters.

    public AbstractHolderFragmentPagerAdapter(FragmentManager fm) {
        super(fm);
        fragmentManager = fm;
    }

    private SparseArray<WeakReference<F>> holder = new SparseArray<WeakReference<F>>();

    protected void holdFragment(F fragment) {
        holdFragment(holder.size(), fragment);
    }

    protected void holdFragment(int position, F fragment) {
        if (fragment != null)
            holder.put(position, new WeakReference<F>(fragment));
    }

    public F getHoldedItem(int position) {
        WeakReference<F> ref = holder.get(position);
        return ref == null ? null : ref.get();
    }

    public int getHolderCount() {
        return holder.size();
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) { // code inspired by Google's FragmentStatePagerAdapter implementation
        super.restoreState(state, loader);
        Bundle bundle = (Bundle) state;
        for (String key : bundle.keySet()) {
            if (key.startsWith(FRAGMENT_SAVE_PREFIX)) {
                int index = Integer.parseInt(key.substring(FRAGMENT_SAVE_PREFIX.length()));
                Fragment f = fragmentManager.getFragment(bundle, key);
                holdFragment(index, (F) f);
            }
        }
    }

    @Override
    public Parcelable saveState() {
        Bundle state = (Bundle) super.saveState();
        if (state == null)
            state = new Bundle();

        for (int i = 0; i < holder.size(); i++) {
            int id = holder.keyAt(i);
            final F f = getHoldedItem(i);
            String key = FRAGMENT_SAVE_PREFIX + id;
            fragmentManager.putFragment(state, key, f);
        }
        return state;
    }
}
Netimen
la source
1

Le principal obstacle à l'obtention d'une poignée sur les fragments est que vous ne pouvez pas compter sur getItem (). Après un changement d'orientation, les références aux fragments seront nulles et getItem () n'est plus appelée.

Voici une approche qui ne repose pas sur l'implémentation de FragmentPagerAdapter pour obtenir la balise. Remplacez instantiateItem () qui renverra le fragment créé à partir de getItem () ou trouvé à partir du gestionnaire de fragments.

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Object value =  super.instantiateItem(container, position);

    if (position == 0) {
        someFragment = (SomeFragment) value;
    } else if (position == 1) {
        anotherFragment = (AnotherFragment) value;
    }

    return value;
}
Adam
la source
0

Voir cet article sur le retour de fragments de FragmentPagerAdapter. Cela dépend de votre connaissance de l'index de votre fragment - mais cela serait défini dans getItem () (à l'instanciation uniquement)

Communauté
la source
0

J'ai réussi à résoudre ce problème en utilisant des identifiants au lieu de balises. (J'utilise J'ai défini FragmentStatePagerAdapter qui utilise mes Fragments personnalisés dans lesquels j'ai remplacé la méthode onAttach, où vous enregistrez l'id quelque part:

@Override
public void onAttach(Context context){
    super.onAttach(context);
    MainActivity.fragId = getId();
}

Et puis vous accédez simplement au fragment facilement à l'intérieur de l'activité:

Fragment f = getSupportFragmentManager.findFragmentById(fragId);
user2740905
la source
0

Je ne sais pas si c'est la meilleure approche mais rien d'autre n'a fonctionné pour moi. Toutes les autres options, y compris getActiveFragment, ont renvoyé null ou ont provoqué le blocage de l'application.

J'ai remarqué que lors de la rotation de l'écran, le fragment était attaché, je l'ai donc utilisé pour renvoyer le fragment à l'activité.

Dans le fragment:

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
        mListener = (OnListInteractionListener) activity;
        mListener.setListFrag(this);
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement OnFragmentInteractionListener");
    }
}

Puis dans l'activité:

@Override
public void setListFrag(MyListFragment lf) {
    if (mListFragment == null) {
        mListFragment = lf;
    }
}

Et enfin dans l'activité onCreate ():

if (savedInstanceState != null) {
    if (mListFragment != null)
        mListFragment.setListItems(items);
}

Cette approche associe le fragment visible réel à l'activité sans en créer un nouveau.

TacoEater
la source
0

Je ne sais pas si ma méthode était la bonne ou la meilleure façon de le faire puisque je suis un débutant relatif avec Java / Android, mais cela a fonctionné (je suis sûr que cela viole les principes orientés objet mais aucune autre solution n'a fonctionné pour mon cas d'utilisation).

J'avais une activité d'hébergement qui utilisait un ViewPager avec un FragmentStatePagerAdapter. Afin d'obtenir des références aux fragments qui ont été créés par FragmentStatePagerAdapter, j'ai créé une interface de rappel dans la classe de fragment:

public interface Callbacks {
    public void addFragment (Fragment fragment);
    public void removeFragment (Fragment fragment);
}

Dans l'activité d'hébergement, j'ai implémenté l'interface et créé un LinkedHasSet pour garder une trace des fragments:

public class HostingActivity extends AppCompatActivity implements ViewPagerFragment.Callbacks {

    private LinkedHashSet<Fragment> mFragments = new LinkedHashSet<>();

    @Override
    public void addFragment (Fragment fragment) {
        mFragments.add(fragment);
    }

    @Override
    public void removeFragment (Fragment fragment) {
        mFragments.remove(fragment);
    }
}

Dans la classe ViewPagerFragment, j'ai ajouté les fragments à la liste dans onAttach et je les ai supprimés dans onDetach:

public class ViewPagerFragment extends Fragment {

    private Callbacks mCallbacks;

    public interface Callbacks {
        public void addFragment (Fragment fragment);
        public void removeFragment (Fragment fragment);
    } 

    @Override
    public void onAttach (Context context) {
        super.onAttach(context);
        mCallbacks = (Callbacks) context;
        // Add this fragment to the HashSet in the hosting activity
        mCallbacks.addFragment(this);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        // Remove this fragment from the HashSet in the hosting activity
        mCallbacks.removeFragment(this);
        mCallbacks = null;
    }
}

Dans le cadre de l'activité d'hébergement, vous pourrez désormais utiliser mFragments pour parcourir les fragments qui existent actuellement dans FragmentStatePagerAdapter.

sbearben
la source
0

Cette classe fait l'affaire sans s'appuyer sur des balises internes. Attention: les fragments doivent être accédés à l'aide de la méthode getFragment et non de celle getItem.

public class ViewPagerAdapter extends FragmentPagerAdapter {

    private final Map<Integer, Reference<Fragment>> fragments = new HashMap<>();
    private final List<Callable0<Fragment>> initializers = new ArrayList<>();
    private final List<String> titles = new ArrayList<>();

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

    void addFragment(Callable0<Fragment> initializer, String title) {
        initializers.add(initializer);
        titles.add(title);
    }

    public Optional<Fragment> getFragment(int position) {
        return Optional.ofNullable(fragments.get(position).get());
    }

    @Override
    public Fragment getItem(int position) {
        Fragment fragment =  initializers.get(position).execute();
        return fragment;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        fragments.put(position, new WeakReference<>(fragment));
        return fragment;
    }

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

    @Override
    public CharSequence getPageTitle(int position) {
        return titles.get(position);
    }
}
Alex Miragall
la source
-5

Continuez d'essayer ce code,

public class MYFragmentPAdp extends FragmentPagerAdapter {

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

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

     @Override
     public Fragment getItem(int position) {
         if (position == 0)
             Fragment fragment = new Fragment1();
         else (position == 1)
             Fragment fragment = new Fragment2();
         return fragment;
     }
}
Najib Ahmed Puthawala
la source
Najib, comme je l'ai expliqué dans ma réponse ci-dessous, getItem () crée un nouveau fragment au lieu de renvoyer des fragments existants comme on pourrait s'attendre à ce que le nom donné soit obtenu et non créé . Voir ma solution dans le même post.
Ismar Slomic
Fragment fragment = new YourCustomFragmentClass (); écrivez ici vérifiez pour cela.
Najib Ahmed Puthawala
Je ne comprends toujours pas comment cela change le fait que vous créez un nouveau fragment au lieu d'en obtenir un existant ..
Ismar Slomic
Vous initialisez et retournez toujours pour votre fragment personnalisé uniquement, comme Fragment fragment = new YourFragment (); retour fragment;
Najib Ahmed Puthawala