web-dev-qa-db-fra.com

Revenir à FragmentPagerAdapter -> les fragments sont vides

J'ai un fragment (je l'appellerai pagerFragment) qui est ajouté au backstack et est visible. Il contient un viewPager avec un FragmentPagerAdapter. Le FragmentPagerAdapter contient (disons) deux fragments: A et B.

Le premier ajout des fragments fonctionne très bien.

Le fragment A a un bouton qui, une fois cliqué, ajoute un fragment (C) au backstack.

Le problème est le suivant: si j'ajoute ce fragment (C), puis clique en arrière, le pagerAdapter est vide et je ne vois aucun fragment à l'intérieur.

Si j'utilise un hack et détruis les fragments enfants (A et B) dans la pagerFragments onDestroyView(), cela résout le problème, bien que je ne veuille pas utiliser ce hack.

Des idées sur le problème?

58
Amit Ishai

J'ai eu le même problème. La solution pour moi était simple:

dans onCreateView j'avais:

// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(getActivity()
    .getSupportFragmentManager());

où SectionPageAdapter est quelque chose comme ceci:

class SectionsPagerAdapter extends FragmentPagerAdapter {
...
}

après avoir remplacé getSupportFragmentManager par

mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager());

ça a commencé à fonctionner! J'espère que cela t'aides.

85
Mike Mitterer

Il semble que vous utilisiez des fragments imbriqués puisque votre ViewPager est à l'intérieur d'un PagerFragment. Avez-vous transmis getChildFragmentManager () au constructeur de votre FragmentPagerAdapter? Sinon, vous devriez.

Je ne pense pas que vous ayez besoin d'un FragmentStatePagerAdapter, mais je donnerais une chance car il gère l'enregistrement et la restauration de l'état du fragment. Le fait que votre hack onDestroyView () fonctionne me fait penser que vous voudrez peut-être un FragmentStatePagerAdapter.

Cela pourrait également avoir quelque chose à voir avec la façon dont FragmentPagerAdapter ajoute des fragments. FragmentPagerAdapter n'ajoute pas de fragments au backstack. Imaginez si vous aviez plus de 10 pages ajoutées dans votre ViewPager et que l'utilisateur les parcourait. L'utilisateur devrait riposter 11 fois juste pour se retirer de l'application.

Il peut également être lié à ce message: Fragments imbriqués et The Back Stack .

De plus, je ne sais pas à quoi vous ajoutez le fragment C. L'ajoutez-vous au même conteneur que le ViewPager?

Eh bien, au moins, vous avez quelques options à étudier. Dans ces situations, j'aime déboguer vers le bas dans le code source du SDK Android et voir ce qui cause le problème. Je recommande de saisir le source AOSP et d'ajouter des frameworks/support et frameworks/base en tant que sources du SDK. C'est la seule véritable façon de comprendre ce qui se passe et d'éviter de faire des changements aléatoires jusqu'à ce que les choses fonctionnent.

15

Je viens aussi de faire face au problème dans notre projet. La cause première est la façon dont le FragmentPagerAdapter fonctionne:

Le FragmentPagerAdapter détache simplement un fragment dont il n'a pas besoin actuellement de sa vue mais ne le supprime pas de son FragmentManager. Lorsqu'il souhaite afficher à nouveau le fragment, il vérifie si le FragmentManager contient toujours le fragment à l'aide d'une balise créée à partir de l'ID d'affichage du ViewPager et de l'ID renvoyé par l'appel des adaptateurs getItemId (position). S'il trouve un fragment, il planifie simplement une connexion du fragment à sa vue dans la transaction de mise à jour du FragmentManager. Seulement s'il ne trouve pas un fragment de cette façon, il en crée un nouveau en utilisant l'appel getItem (position) de l'adaptateur!

Le problème avec un fragment contenant un ViewPager avec un FragmentPagerAdapter est que le contenu du FragmentManager n'est jamais nettoyé lorsque le fragment contenant est placé dans la pile arrière. Si le fragment contenant revient de la pile arrière, il crée une nouvelle vue mais le FragmentManager contient toujours les fragments qui étaient attachés à l'ancienne vue et l'attachement d'un fragment existant ne fonctionne plus.

Le moyen le plus simple de se débarrasser de ce problème est d'éviter les fragments imbriqués. :)

La deuxième façon la plus simple est, comme déjà mentionné dans d'autres articles, d'utiliser le ChildFragmentManager pour le FragmentPagerAdapter car celui-ci est correctement mis à jour pendant le cycle de vie du fragment de conteneur.

Comme il existe des projets (comme le mien) où les deux options ne sont pas possibles, j'ai publié ici une solution qui fonctionne avec un FragmentManager arbitraire en utilisant le hashCode des sous-fragments comme identifiant du fragment à cette position. Il vient au prix de stocker tous les fragments pour toutes les positions dans l'adaptateur.

public class MyPagerAdapter extends FragmentPagerAdapter {

private static int COUNT = ...;
private final FragmentManager fragmentManager;
private Fragment[] subFragments = new Fragment[COUNT];
private FragmentTransaction cleanupTransaction;

public MyPagerAdapter(FragmentManager fragmentManager) {
    super(fragmentManager);
    this.fragmentManager = fragmentManager;
}

@Override
public Fragment getItem(int position) {
    return getSubFragmentAtPosition(position);
}

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

@Override
public long getItemId(int position) {
    return getSubFragmentAtPosition(position).hashCode();
}

//The next three methods are needed to remove fragments no longer used from the fragment manager
@Override
public void startUpdate(ViewGroup container) {
    super.startUpdate(container);
    cleanupTransaction = fragmentManager.beginTransaction();
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    cleanupTransaction.remove((Fragment) object);
}

@Override
public void finishUpdate(ViewGroup container) {
    super.finishUpdate(container);
    cleanupTransaction.commit();
}

private Fragment getSubFragmentAtPosition(int position){
    if (subFragments[position] == null){
        subFragments[position] = ...;
    }
    return subFragments[position];
}

}

1
Nantoka

Utilisez getChildFragmentManager() au lieu de getSupportFragmentManager(). Cela fonctionnera bien.

0
vijay rathore

J'ai eu le même problème, il suffit de régler l'adaptateur deux fois de suite et c'est tout.

Exemple de code:

private fun displayImg(photo1:String, photo2:String){
    val pager:ViewPager = v?.findViewById(R.id.ProductImgPager)!!
    val arr = ArrayList<String>()
    arr.add(photo1)
    arr.add(photo2)
    pager.adapter = AdapterImageView(fm, arr ,arr.size)
    pager.adapter = AdapterImageView(fm, arr ,arr.size)

}
0
Biplob Das