FragmentPagerAdapter getItem n'est pas appelé

123

Je ne suis pas en mesure de réutiliser le fragment dans FragmentPagerAdapter .. En utilisant la méthode destroyItem (), il supprime le fragment mais n'appelle toujours pas getItem () à nouveau .. Il n'y a que 2-3 images donc j'utilise FragmentPagerAdapter au lieu de FragmentStatePagerAdapter ..

public class ExamplePagerAdapter extends FragmentPagerAdapter {

    ArrayList < String > urls;
    int size = 0;
    public ExamplePagerAdapter(FragmentManager fm, ArrayList < String > res) {
        super(fm);
        urls = res;
        size = urls.size();
    }

    @Override
    public int getCount() {
        if (urls == null) {
            return 0;
        } else {
            return size;
        }

    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        FragmentManager manager = ((Fragment) object).getFragmentManager();
        FragmentTransaction trans = manager.beginTransaction();
        trans.remove((Fragment) object);
        trans.commit();
    }

    @Override
    public Fragment getItem(int position) {

        Fragment fragment = new FloorPlanFragment();
        Bundle b = new Bundle();
        b.putInt("p", position);
        b.putString("image", urls.get(position));
        Log.i("image", "" + urls.get(position));
        fragment.setArguments(b);
        return fragment;
    }
}

Et dans FragmentActivity,

pager.setAdapter(new ExamplePagerAdapter(getSupportFragmentManager(), res2)); 
Kanika
la source
3
Y a-t-il une raison particulière pour laquelle vous avez passé outre destroyItem()? Ce n'est pas nécessaire.
CommonsWare
pour initialiser à nouveau, utilisez FragmentStatePagerAdapter également appelez lorsque vous le remplacez super.destroyItem (conteneur, position, objet);
faiziii

Réponses:

306

Réponse KISS:

Utilisez simplement FragmentStatePagerAdapter au lieu de FragmentPagerAdapter .

J'ai eu la réponse .. Tout d'abord, j'ai pensé supprimer cette question car je fais une erreur très idiote, mais cette réponse aidera quelqu'un qui est confronté au même problème qu'au lieu d' FragmentPagerAdapterutiliser FragmentStatePagerAdapter.

Comme @BlackHatSamurai l'a mentionné dans le commentaire:

La raison pour laquelle cela fonctionne est parce que FragmentStatePagerAdapterdétruit en tant que fragments qui ne sont pas utilisés. FragmentPagerAdapterne fait pas.

Kanika
la source
Merci beaucoup.Ur réponse m'a beaucoup aidé.
Priya
1
Je déteste être un autre moi aussi! post, mais ouais>. <Merci de ne pas avoir supprimé la question.
Paul Ruiz
34
La raison pour laquelle cela fonctionne est que FragmentStatePagerAdapter détruit en tant que fragments qui ne sont pas utilisés. FragmentPagerAdapter ne le fait pas.
BlackHatSamurai
3
Juste pour référence future pour ceux qui peuvent trouver cela en recherchant un problème spécifique qu'ils rencontrent; lire à la fois sur FragmentPagerAdapter et FragmentStatePagerAdapter. Ils se comportent différemment pour une raison et votre utilisation spécifique peut nécessiter l'un sur l'autre.
Chris Stewart
2
@najibputhawala J'ai utilisé FragmentStatePagerAdapter mais je suis toujours confronté au même problème. getItem () not called
sam_k
168

L'utilisation d'un FragmentStatePagerAdaptern'a pas complètement résolu mon problème qui était un problème similaire où onCreateViewil n'y avait pas d'appel pour les fragments enfants dans le pager de vue. Je suis en fait en train de nicher mon FragmentPagerAdapterintérieur dans un autre,Fragment donc le a FragmentManagerété partagé entre tous et donc en conservant des exemples des anciens fragments. Le correctif consistait à alimenter à la place une instance de the getChildFragmentManagerau constructeur du FragmentPagerAdapterfragment in my host. Quelque chose comme...

FragmentPagerAdapter adapter = new FragmentPagerAdapter(getChildFragmentManager());

La getChildFragmentManager()méthode est accessible via un fragment et cela a fonctionné pour moi car elle renvoie un privé FragmentManagerpour ce fragment spécifiquement pour les situations dans lesquelles l'imbrication de fragments est nécessaire. J'espère que cela aide quelqu'un qui peut avoir le même problème que moi !!

  • Gardez à l'esprit cependant que pour utiliser getChildFragmentManager()votre version minimale de l'API doit être au moins 17 (4.2), cela peut donc vous gâcher. Bien sûr, si vous utilisez des fragments de la bibliothèque de support v4, vous devriez être d'accord.
Jraco11
la source
25
C'est la bonne réponse. Le problème est dû au fait que les fragments imbriqués dans d'autres fragments doivent utiliser getChildrenFragmentManager () au lieu de getFragmentManager ().
shihpeng
Merci beaucoup, il m'a fallu une éternité pour trouver cette réponse!
Shpongoloid
Je suis d'accord avec @shihpeng. Cela devrait être la bonne réponse.
Raymond Lukanta du
Celui-ci était une solution pour moi. Merci beaucoup d'avoir soumis une réponse
user3734429
La documentation devrait vraiment appeler cela dans le walk-thru. Il est très réaliste qu'un ViewPager soit chargé dans un fragment. Merci d'avoir publié cette réponse.
travaillé
7

Passer outre long getItemId (int position)

FragmentPagerAdaptermet en cache les fragments qu'il crée à l'aide de getItem. J'étais confronté au même problème - même après avoir appelé notifyDataSetChanged() getItemn'était pas appelé.

Il s'agit en fait d'une fonctionnalité et non d'un bogue. Vous devez remplacer getItemIdafin de pouvoir réutiliser correctement vos fragments. Depuis que vous supprimez des fragments, vos positions changent. Comme mentionné dans la documentation:

long getItemId (int position)

Renvoie un identifiant unique pour l'article à la position donnée.

L'implémentation par défaut renvoie la position donnée. Les sous-classes doivent remplacer cette méthode si les positions des éléments peuvent changer.

Fournissez simplement un identifiant unique à chaque fragment et vous avez terminé.

L' utilisation d' un FragementStatePagerAdapterou de retour POSITION_NONEen int getItemPosition (Object object)est erroné. Vous n'obtiendrez aucune mise en cache.

védant
la source
Celui-ci était la bonne réponse. J'ai dû fournir des identifiants différents pour les fragments dans getItemIdAND ajuster getItemPositionpour retourner POSITION_NONESI le fragment devait être supprimé. J'ai un indicateur d'énumération pour cela. Après cela getItemsera appelé.
Murat Karagöz le
Merci @ MuratKaragöz pour le +50 :)
vedant
5

J'ai fait ce que @kanika et @ Jraco11 avaient publié mais j'avais toujours le problème.

Donc, après de nombreux changements, j'en ai trouvé un qui fonctionnait pour moi et a été ajouté à mon FragmentPagerAdapter le code suivant:

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

Selon ce que j'ai lu, getItemPosition est utilisé pour notifier au ViewPager s'il faut ou non actualiser un élément, et pour éviter les mises à jour si les éléments aux positions visibles n'ont pas changé.

Jorge Casariego
la source
2

Il existe deux scénarios différents: 1.) Vous avez la même disposition pour chaque pager: dans ce cas, il sera préférable d'étendre votre adaptateur personnalisé par PagerAdapter et de renvoyer une seule disposition.

2.) Vous avez une disposition différente pour chaque pager: dans ce cas, il sera préférable d'étendre votre adaptateur personnalisé par FragmentStatePagerAdapter et de renvoyer différents fragmets pour chaque pager.

Maddy
la source
2

La méthode getItem()est utilisée uniquement pour créer de nouveaux éléments. Une fois qu'ils ont été créés, cette méthode ne sera pas appelée. Si vous avez besoin d'obtenir un article qui est la devise utilisée par l'adaptateur, utilisez cette méthode:

pagerAdapter.instantiateItem(viewPager, TAB_POS)
B-GangsteR
la source
0

J'ai trouvé que la configuration d'un écouteur sur la mise en page des onglets a empêché cet appel, probablement parce qu'ils n'ont de l'espace que pour un auditeur au tabLayout.setOnTabSelectedListenerlieu d'un tableau d'écouteurs.

Oliver Dixon
la source