55 votes

Afficher le viewpager du fragment dans un fragment

J'ai un fragment qui contient un ViewPager. Le ViewPager est associé à un adaptateur qui contient un ensemble de fragments.

Au moment de charger le fragment parent, je suis confronté à une IllegalStateException avec le message : java.lang.IllegalStateException: Recursive entry to executePendingTransactions .

Quelques recherches m'ont amené à la conclusion que le système est incapable d'afficher des fragments à l'intérieur d'un autre fragment. CEPENDANT, il semble qu'il soit possible de faire exactement cela en utilisant un ViewPager ( Un bug dans le ViewPager en l'utilisant avec un autre fragment ).

En fait, si j'ajoute un bouton à mon fragment parent qui appelle mPager.setAdapter(mAdapter) sur mon ViewPager lorsqu'on appuie dessus, le ViewPager se charge avec succès. Ce n'est pas idéal.

Le problème doit donc être lié au cycle de vie des fragments. Ma question est donc la suivante : Quelqu'un d'autre a-t-il trouvé un moyen de contourner ce problème, et si oui, comment ?

Existe-t-il un moyen de retarder le paramétrage de l'adaptateur sur le ViewPager jusqu'après la transaction du fragment ?

Voici le code de mon fragment de parent :

    @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

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

    final Button button = (Button)mView.findViewById(R.id.load_viewpager_button);
    button.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            mViewPager.setAdapter(mAdapter);
            button.setVisibility(View.GONE);
        }
    });

    mAdapter = new ViewPagerAdapter(getFragmentManager());
 //     mViewPager.setAdapter(mAdapter);

    return mView;
}

Et l'adaptateur :

public class ViewPagerAdapter extends FragmentPagerAdapter {
    public ViewPagerAdapter(FragmentManager fm) {
        super(fm);
    }

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

    @Override
    public Fragment getItem(int position) {
        Bundle b = createBundle(position, mCursor);
        return TeamCardFragment.newInstance(b);
    }
}

8 votes

La possibilité d'imbriquer des fragments a été ajoutée dans la révision 11 de la bibliothèque Android Support. La classe Fragment possède maintenant la méthode "getChildFragmentManager" . J'ai créé un projet simple similaire à celui-ci qui peut être trouvé à l'adresse suivante github.com/marsucsb/nested-fragments

0 votes

stackoverflow.com/q/18097567/1503130 Pouvez-vous m'aider ?

60voto

Yashwanth Kumar Points 12122

Utiliser AsyncTask pour définir l'adaptateur pour viewPager. Cela fonctionne pour moi. L'asyncTask sert à faire en sorte que le fragment original termine sa transition, puis nous procédons avec les fragments viewPager, essentiellement pour éviter la récursion.

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

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

    final Button button = (Button)mView.findViewById(R.id.load_viewpager_button);
    button.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            mViewPager.setAdapter(mAdapter);
            button.setVisibility(View.GONE);
        }
    });

    mAdapter = new ViewPagerAdapter(getFragmentManager());
    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);
        }
}

0 votes

Ok- pas si parfait. J'avais un problème où les vues dans le viewpager étaient noires quand la vue avait été recréée - puisque les fragments à l'intérieur sont réutilisés. Je l'ai résolu avec ce code dans le onDestroyView du fragment :

1 votes

Int position = 0 ; for (TabInfo info : mTabsAdapter.mTabs) { String tag = FragmentPagerAdapter.makeFragmentName(mViewPager.getId(), position) ; Fragment fragment ; FragmentTransaction ft = getSupportFragmentManager().beginTransaction() ; if ((fragment = getFragmentManager().findFragmentByTag(tag)) != null) { [...]

7 votes

Veuillez utiliser getChildFragmentManger() cette solution est bien meilleure

39voto

Lecho Points 2807

Vous pouvez utiliser FragmentStatePagerAdapter au lieu de FragmentPageAdapter . Il supprimera les fragments pour vous.

26voto

Steven Byle Points 4888

Je viens de rencontrer le même problème. J'avais un Fragment qui devait accueillir un ViewPager de Fragments . Quand j'ai empilé un autre Fragment sur le dessus de mon ViewPagerFragment et que j'ai répliqué, j'ai eu un IllegalStateException . Après avoir vérifié les billes (lors de l'empilage d'un nouveau Fragment ), j'ai constaté que mon ViewPagerFragment passerait par ses méthodes de cycle de vie pour s'arrêter et se détruire, cependant ses enfants Fragments dans le ViewPager resterait dans onResume . J'ai réalisé que les enfants Fragments devraient être gérés par le FragmentManager pour le ViewPagerFragment et non le FragmentManager de la Activity .

Je crois savoir qu'à l'époque, les réponses ci-dessus visaient à contourner les limites de l'application de la loi. Fragments ne pas pouvoir avoir d'enfants Fragments . Toutefois, maintenant que la dernière bibliothèque de support prend en charge les éléments suivants Fragment vous n'avez plus besoin de bidouiller la configuration de l'adaptateur pour votre ViewPager et en passant getChildFragmentManager() est tout ce dont vous avez besoin. Cela a parfaitement fonctionné pour moi jusqu'à présent.

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

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

    mAdapter = new ViewPagerAdapter(getChildFragmentManager());
    mViewPager.setAdapter(mAdapter);

    return mView;
}

0 votes

Cela devrait être la réponse acceptée pour les versions récentes d'Android.

0 votes

GetChildFragmentManager est pour le fragment Comment puis-je résoudre le problème dans l'activité ?

0 votes

@Milad si le Activity gère un ViewPager de Fragments il suffit de passer le Activity 's FragmentManager ( getFragmentManager() ) à la Adapter

19voto

inazaruk Points 37760

J'ai utilisé Handler.post() pour définir l'adaptateur en dehors de la transaction du fragment original :

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            mViewPager.setAdapter(mAdapter);     
        }
    });        
}

1 votes

D'où vient ce mHandler ?

0 votes

Il devrait être un membre et vous pouvez l'instancier dans onCreate() : mHandler = new Handler();

2 votes

Cette approche pose-t-elle des problèmes pour passer d'un fragment à l'autre ? J'ai actuellement un problème si je vais dans un autre fragment et que je reviens à celui qui contient le ViewPager. Le contenu ne s'affiche pas et le défilement n'est pas correct.

0voto

Sanket Points 11

J'ai rencontré ce problème lorsque j'ai essayé d'initialiser l'adaptateur viewPager sur le TabIndicator dans ViewCreated. Après avoir lu sur le sujet en ligne, j'ai réalisé que cela pouvait être dû au fait que le fragment n'avait pas encore été ajouté à l'activité. J'ai donc déplacé le code d'initialisation vers onStart() du fragment, ce qui devrait résoudre votre problème. Mais pas pour moi, j'ai encore eu le même problème.

Mais c'est parce que dans mon code, j'ai essayé de contourner l'exécution asynchrone normale des tâches en attente en appelant explicitement executePendingTransactions(), après avoir bloqué cela, tout a bien fonctionné.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X