Le fragment dans ViewPager à l'aide de FragmentPagerAdapter est vide la deuxième fois qu'il est affiché


98

J'ai une interface de fragment avec des onglets en bas qui ouvrent différents fragments dans la vue principale.

J'ai un fragment particulier qui est une liste d'articles. Si l'utilisateur sélectionne l'un des éléments de cette liste, un autre fragment s'ouvre et contient un visualiseur qui défile horizontalement entre tous les éléments de la liste dans le fragment précédent. Cela fonctionne très bien.

Le visualiseur utilise un FragmentPagerAdapter pour afficher les éléments.

Le problème survient lorsque l'utilisateur sélectionne un élément dans la liste, l'affiche, puis appuie sur le bouton de la barre d'onglets pour revenir à la liste, puis sélectionne un autre élément. La deuxième fois qu'un élément est sélectionné, un écran vide apparaît à la place du visualiseur. Je ne reçois aucune erreur dans mon LogCat lorsque cela se produit.

Pourquoi le visualiseur n'apparaît-il que la première fois?

FragmentPagerAdapter:

public class ViewPagerAdapter extends FragmentPagerAdapter {
    Cursor mCursor;

    public ViewPagerAdapter(FragmentManager fm, Cursor c) {
        super(fm);
        mCursor = c;
    }

    public void changeCursor(Cursor c) {
        mCursor = c;
        this.notifyDataSetChanged();
    }

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

    @Override
    public Fragment getItem(int position) {
        mCursor.moveToPosition(position);
        return TeamCardFragment.newInstance(mCursor, position);
    }
}

PagerFragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);

    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);

    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();

    return mView;
}

private class setAdapterTask extends AsyncTask<Void, Void, Void> {
    protected Void doInBackground(Void... params) {
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        mViewPager.setAdapter(mAdapter);
        mViewPager.setCurrentItem(mCursorPosition);
    }
}

Réponses:


221

J'ai eu le même problème. Modification de la classe parente de mon PageAdapter android.support.v4.app.FragmentPagerAdapterpour android.support.v4.app.FragmentStatePagerAdapterrésoudre mon ViewPagerproblème d'affichage la "deuxième fois"!


2
Sans blague? Je n'ai plus ce code sinon je le testerais. Peut-être que cette réponse aidera quelqu'un d'autre.
howettl

10
Quel homme! J'étais à l'affût de cette solution pendant des jours! Merci un homme de tonne, fonctionne comme un charme. Mais le développeur en moi se demande quel est l'impact de ce changement? Je veux dire pourquoi cela n'a pas fonctionné avant et pourquoi dans StatePagerAdapter
Anand Sainath

1
vous devez également @Override public int getItemPosition (Object object) {return POSITION_NONE; }
Helin Wang

1
A travaillé pour moi aussi. Voici un lien. Cela semble sauver l'état du fragment, ce qui fait toute la différence. developer.android.com/reference/android/support/v4/app/…
Tjaart

1
C'est une coïncidence que cela fonctionne, la bonne réponse est celle de @Daniel F. Quoi qu'il en soit, pour la commodité des commentateurs ici, la différence entre FragmentPagerAdapteret FragmentStatePagerAdapterest dans le premier étant plus adapté pour quelques pages, il conserve tous les fragments en mémoire ayant ainsi les meilleures performances sur le changement de page, tandis que le dernier est plus adapté à beaucoup de pages, il détruit les fragments, ne gardant que leur état, c'est plus efficace en mémoire mais un peu plus lent au changement de page.
Cristina De Rito

87

J'ai réussi à résoudre ce problème en remplaçant getFragmentManager()par getChildFragmentManager()dans le fragment parent. Ce fragment parent instanciait un android.support.v4.app.FragmentPagerAdapter afin de contenir des fragments paginables (glissants), ce qui nécessite un gestionnaire de fragments dans le constructeur. À ce constructeur, j'ai passé la valeur de retour de getChildFragmentManager().

Le lien de hackbod était essentiel ( https://developer.android.com/about/versions/android-4.2.html#NestedFragments ), qui a été trouvé dans cet article Fragments within Fragments

Pour imbriquer un fragment, appelez simplement getChildFragmentManager()le fragment dans lequel vous souhaitez ajouter un fragment. Cela renvoie un FragmentManager que vous pouvez utiliser comme vous le faites normalement à partir de l'activité de niveau supérieur pour créer des transactions de fragment.


Merci ... J'avais un problème similaire en essayant de ré-instancier une vue d'onglets coulissants après onresume () qui contenait un fragmentpageradapter ... le didacticiel que j'ai utilisé datait de 2016 et j'avais encore besoin de le changer en fragmentstatepageradapter pour l'obtenir travail. J'aimerais savoir POURQUOI.
Nerdy Bunz

cette réponse m'a fait gagner beaucoup de temps. Car seule l'utilisation ne FragmentStatePagerAdapterrésout pas la question posée ici. avec le FragmentStatePagerAdapterfragment parent YourAdapter adapter = new YourAdapter (getChildFragmentManager()); doit être ajouté
MMK

17

pour moi, je devais appeler ceci sur mon viewpager:

myViewPager.setSaveFromParentEnabled(false);

J'ai eu le problème où le viewpager n'était pas rafraîchissant et tout ce que j'ai vu était un écran blanc vierge où les fragments devraient être. Je passais dans getChildFragmentManager mais cela n'a pas aidé.


1
Pourquoi diable cela a-t-il fonctionné? Cela a résolu mon problème, mais je n'ai aucune idée pourquoi.
ClayHerendeen

Je l'ai supprimé de mon code maintenant. Le gestionnaire de fragments était à l'origine du problème. Essayez de basculer entre getchildfragmentmanager et getfragmentmanager
j2emanue

J'ai déjà essayé cela. J'ai des onglets imbriqués chacun avec des ViewPagers qui ont désactivé le balayage. Je sais que c'est une conception médiocre, mais les clients ne souhaitent pas le mien. Im utilisant un childFragmentManager pour la barre d'onglets de niveau supérieur. Le basculement vers la barre d'onglets / viewpager de niveau inférieur ne semble pas résoudre le problème. Je suppose que je vais m'en tenir à setSaveFromParentEnabled (false) pour le moment car cela fonctionne.
ClayHerendeen

Utilisez-vous la dernière bibliothèque de support
j2emanue

2
J'étais confronté au même problème depuis 2 jours. Votre solution a fonctionné pour moi. Merci !
brijexecon le

11

Dans mon cas très particulier, où j'utilisais un CoordinatorLayout avec un AppBarLayout et le ViewPager, ce qui l'a résolu pour moi était de supprimer l'android: fitSystemWindows = "true" de mes propriétés xml AppBarLayout .

Ne me demandez pas pourquoi. Je sais que cela semble un peu ridicule et que cela ne devrait pas avoir de corrélation, mais c'était cette seule ligne la seule chose qui causait des problèmes car j'utilisais déjà getChildFragmentManager () dans mon adaptateur. J'ai passé une journée entière à déboguer mon code juste pour trouver ceci, donc j'espère que cela fera gagner du temps à quelqu'un d'autre.


3
Oh mec ... J'allais presque me rendre avec ce problème. Vous avez fait ma journée effrayante! Geez Google, WTF a tort avec l'AppBarLayout? J'ai regardé près de cent pages et passé une tonne d'heures à déboguer en essayant de résoudre ce problème sans chance. Je suis vraiment reconnaissant d'avoir enfin réussi à résoudre le problème avec votre commentaire. Merci beaucoup! PS: J'étais tellement désespéré que j'ai même créé un problème dans l'AOSP: code.google.com/p/android/issues/… XD
Guillem Roca

Merci pour l'indice. Au moins, cela nous a aidés à résoudre le problème. Maintenant, nous essayons de trouver une option pour le rendre en plein écran
Paresh Mayani

Tu es un sauveur! Je ne savais absolument pas pourquoi j'avais ce problème et je ne savais toujours pas pourquoi cela fonctionnait!
nandu

10

J'ai eu le même problème pour lequel j'ai changé l'adaptateur de FragmentPagerAdaptervers FragmentStatePagerAdapteret getFragmentManager()dans le fragment parent engetChildFragmentManager()

La raison derrière cela est FragmentStatePagerAdapterutile pour stocker un grand nombre de pages et la mémoire associée à chaque page visitée est moindre car elle ne conserve que l'état enregistré du fragment pendant que la page n'est pas visible. Cela réduit les frais généraux lors de la commutation entre les fragments.


4

Essayez de mettre setOffscreenPageLimit (int limit)sur ViewPager parent.

mViewPager.setOffscreenPageLimit(totalPages-1);

Cela a fonctionné pour moi comme un charme.

Dans mon cas, j'avais un fragment à l'intérieur TabLayoutavecViewPager.

Et un autre à l' ViewPagerintérieur de ce fragment. La première fois, tout fonctionne bien, mais lorsque je change d'onglet et que je reviens, une partie de mon fragment est devenue vierge.


1
Bonne réponse. Cela m'a aidé.
Thirumalvalavan


1

Nous avons contourné ce problème en réimplémentant les éléments du pagineur de vues en tant que vues standard plutôt qu'en fragments et en modifiant l'adaptateur en conséquence.


vous pouvez essayer de supprimer la fonction isViewFromObject (vue vue, objet objet)
Mina Samy

Il doit y avoir un meilleur moyen ....: / bien que plus je fouille dans Android, moins je me rends compte que c'est.
StackOverflowed

1
Les fragments imbriqués ne sont pas pris en charge , donc la réimplémentation avec la vue standard semble la bonne voie à suivre.
Sylphe le

Je lutte avec un problème similaire. J'ai essayé d'utiliser PagerAdapter au lieu de FragmentAdapter, mais je rencontre le même problème. Sil te plait aide moi !
Gaurav Arora

Si vous souhaitez utiliser des fragments imbriqués, vous pouvez utiliser l'adaptateur que j'ai fourni dans cette réponse: stackoverflow.com/questions/7700226/…
Slickelito

1

J'obtenais ce même problème sur Xamarin Android avec un écran vide la deuxième fois. La configuration de ce qui suit l'a corrigé pour moi.

viewPager.SaveFromParentEnabled = false;

0

Vous pouvez également initialiser l'adaptateur pour les cas où vous rencontrez cette erreur lorsque votre application est réduite et appelée ultérieurement.

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    Bundle bundle = getArguments();
    mCursorPosition = bundle.getInt(TeamCardCommon.BUNDLE_KEY_CURSOR_POSITION);
    View mView = inflater.inflate(R.layout.team_card_master, container, false);
    mViewPager = (ViewPager)mView.findViewById(R.id.team_card_master_view_pager);
    initViewPagerAdapter();
    return mView;
}
private void initViewPagerAdapter(){
    mAdapter = new ViewPagerAdapter(getFragmentManager(), cursor);
    new setAdapterTask().execute();
}

@Override
public void onResume(){
    super.onResume();
    initViewPagerAdapter();
}

0

J'ai eu la même chose, la deuxième fois que j'appelle l'adaptateur de téléavertisseur, la vue enfant renvoie une NullPointerException. Et changer l'adaptateur dans FragmentStatePagerAdapter résout également mon problème.


0

Changer FragmentPagerAdapteren FragmentStatePagerAdapter utilisation getChildFragmentManager()au lieu degetFragmentManager()

getChildFragmentManager()- car selon la documentation, il renverra un FragmentManager privé pour placer et gérer des fragments à l'intérieur de ce fragment. Pendant ce temps getFragmentManager(), retournera le FragmentManager pour interagir avec les fragments associés à cette activité


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.