Afficher le visualiseur de fragments dans un fragment

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

Lors du chargement du fragment parent, je rencontre une IllegalStateException avec le message: java.lang.IllegalStateException: Recursive entry to executePendingTransactions .

Certaines recherches m’ont amené à la conclusion que le système ne pouvait pas afficher des fragments dans un autre fragment, mais il semble y avoir une indication qu’il est possible de faire exactement cela avec l’utilisation d’un ViewPager ( un bogue dans ViewPager l’utilisant avec un autre fragment). ).

En fait, si j’ajoute un bouton à mon fragment parent qui appelle mPager.setAdapter(mAdapter) sur mon ViewPager, le ViewPager se charge correctement. Ce n’est pas idéal.

Le problème doit alors ê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 les parameters de l’adaptateur sur ViewPager avant la transaction de fragment?

Voici mon code 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); } } 

utilisez AsyncTask pour définir l’adaptateur pour viewPager. Ça marche pour moi. AsyncTask doit permettre au fragment original de terminer sa transition. et ensuite nous procédons avec des fragments de viewPager, essentiellement pour éviter la récursivité.

  @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{ protected Void doInBackground(Void... params) { return null; } @Override protected void onPostExecute(Void result) { mViewPager.setAdapter(mAdapter); } } 

Jords, je pense que vous pouvez utiliser FragmentStatePagerAdapter au lieu de FragmentPageAdapter . Cela enlèvera des fragments pour vous.

PS Désolé pour l’utilisation de la réponse au lieu du commentaire mais ma réputation est trop faible.

Je viens de rencontrer ce même problème. J’avais un Fragment qui devait héberger un ViewPager de Fragments . Lorsque j’ai empilé un autre Fragment au-dessus de mon ViewPagerFragment , puis que je le ViewPagerFragment , ViewPagerFragment . Après avoir vérifié les journaux (lors de l’emstackment d’un nouveau Fragment ), j’ai constaté que mon ViewPagerFragment ses méthodes de cycle de vie pour s’arrêter et détruire, mais ses Fragments enfants dans le ViewPager restraient dans onResume . J’ai réalisé que les Fragments enfants devraient être gérés par le FragmentManager pour le ViewPagerFragment , pas le FragmentManager de l’ Activity .

Je comprends à l’époque, les réponses ci-dessus devaient contourner les limites des Fragments ne pouvant pas avoir d’enfants Fragments . Cependant, maintenant que la dernière bibliothèque de support prend en charge l’imbrication de Fragment , vous n’avez plus besoin de ViewPager la configuration de l’adaptateur pour votre ViewPager , et vous n’avez besoin que de transmettre getChildFragmentManager() . Cela a fonctionné parfaitement 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; } 

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

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

J’ai rencontré ce problème en essayant d’initialiser l’adaptateur viewPager sur le TabIndicator dans ViewCreated. Après avoir lu à ce sujet en ligne, je me suis rendu compte que cela pouvait être juste parce que le fragment n’avait pas encore été ajouté à l’activité. J’ai donc déplacé le code d’initialisation sur onStart () du fragment, cela devrait résoudre votre problème. Mais pas pour moi, je recevais encore le même problème.

Mais c’était parce que dans mon code, j’essayais de contourner l’exécution asynchrone normale de la tâche en attente en appelant explicitement executePendingTransactions (), après avoir bloqué que tout fonctionnait bien

Lors du chargement du fragment parent, je rencontre une exception IllegalStateException avec le message: java.lang.IllegalStateException: entrée récursive pour exécuterPendingTransactions.

Certaines recherches m’ont amené à la conclusion que le système ne pouvait pas afficher des fragments dans un autre fragment, mais il semble y avoir une indication qu’il est possible de faire exactement cela avec l’utilisation d’un ViewPager (un bogue dans ViewPager l’utilisant avec un autre fragment). ).

définir explicitement Id pour ViewPager.

  @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); mViewPager.setId(100); 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; } 

Vous pouvez utiliser id dans vos ressources XML au lieu d’un chiffre magique 100.

    

et setId (R.Id_For_ViewPager).

Voir la source FragmentManager.java pour plus de détails.

https://github.com/android/platform_frameworks_support/blob/master/v4/java/android/support/v4/app/FragmentManager.java#L900

Ou voir cette page (japonais). L’idée originale vient d’elle, en fait, pas de moi. http://y-anz-m.blogspot.jp/2012/04/androidfragment-viewpager-id.html

En utilisant ce shiny article de Thomas Amssler: http://tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html

Iv’e a créé un adaptateur permettant de créer tous types de fragments. L’adaptateur lui-même ressemble à ceci:

 public abstract class EmbeddedAdapter extends FragmentStatePagerAdapter { private SparseArray> mPageReferenceMap = new SparseArray>(); private ArrayList mTabTitles; public abstract Fragment initFragment(int position); public EmbeddedAdapter(FragmentManager fm, ArrayList tabTitles) { super(fm); mTabTitles = tabTitles; } @Override public Object instantiateItem(ViewGroup viewGroup, int position) { mPageReferenceMap.put(Integer.valueOf(position), new WeakReference(initFragment(position))); return super.instantiateItem(viewGroup, position); } @Override public int getCount() { return mTabTitles.size(); } @Override public CharSequence getPageTitle(int position) { return mTabTitles.get(position); } @Override public Fragment getItem(int pos) { return getFragment(pos); } @Override public void destroyItem(ViewGroup container, int position, Object object) { super.destroyItem(container, position, object); mPageReferenceMap.remove(Integer.valueOf(position)); } public Fragment getFragment(int key) { WeakReference weakReference = mPageReferenceMap.get(key); if (null != weakReference) { return (Fragment) weakReference.get(); } else { return null; } } @Override public int getItemPosition(Object object) { return POSITION_NONE; } 

}

Pour utiliser l’adaptateur, procédez comme suit:

 private void setAdapter() { if(mAdapter == null) mAdapter = new EmbeddedAdapter(getActivity().getSupportFragmentManager(), mTabTitles) { @Override public Fragment initFragment(int position) { Fragment fragment; if(position == 0){ // A start fragment perhaps? fragment = StartFragment.newInstance(mBlocks); }else{ // Some other fragment fragment = PageFragment.newInstance(mCategories.get((position))); } return fragment; } }; // Have to set the adapter in a handler Handler handler = new Handler(); handler.post(new Runnable() { @Override public void run() { mViewPager.setVisibility(View.VISIBLE); mPagerTabSsortingp.setVisibility(View.VISIBLE); mAdapter.notifyDataSetChanged(); } }); } 

Notez que tous les fragments utilisent le:

 setRetainInstance(true); 

Selon la documentation: https://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager ()

Si vous souhaitez gérer le fragment d’imbrication, vous devez utiliser getChildFragmentManager au lieu de getFragmentManager .