tutorial studio inside fragments example change activity android android-fragments android-viewpager android-lifecycle android-nested-fragment

studio - fragment example android



Mostrar fragmento viewpager dentro de un fragmento (8)

Tengo un fragmento que contiene un ViewPager. ViewPager está asociado con un adaptador que contiene un conjunto de fragmentos.

Al cargar el fragmento principal, me encuentro con una IllegalStateException con el mensaje: java.lang.IllegalStateException: Recursive entry to executePendingTransactions .

Algunas investigaciones me han llevado a la conclusión de que el sistema no puede mostrar fragmentos dentro de otro fragmento, SIN EMBARGO parece que hay alguna indicación de que es posible hacer exactamente esto con el uso de un ViewPager ( un error en ViewPager usándolo con otro fragmento )

De hecho, si agrego un botón a mi fragmento principal que llama a mPager.setAdapter(mAdapter) en mi ViewPager cuando se presiona, la ViewPager se carga correctamente. Esto no es ideal

El problema entonces debe estar relacionado con el ciclo de vida del fragmento. Mi pregunta, por lo tanto, es esta: ¿Alguien más ha encontrado una forma de solucionar este problema, y ​​si es así, cómo?

¿Hay alguna forma de retrasar la configuración del adaptador en la ViewPager hasta después de la transacción del fragmento?

Aquí está mi código de fragmento padre:

@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; }

Y el adaptador:

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); } }


Al cargar el fragmento principal, me encuentro con una IllegalStateException con el mensaje: java.lang.IllegalStateException: entrada recursiva para ejecutarPendingTransactions.

Algunas investigaciones me han llevado a la conclusión de que el sistema no puede mostrar fragmentos dentro de otro fragmento, SIN EMBARGO parece que hay alguna indicación de que es posible hacer exactamente esto con el uso de un ViewPager (un error en ViewPager usándolo con otro fragmento )

establecer Id para ViewPager explícitamente.

@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; }

Puede usar la identificación en sus recursos xml en lugar de un número mágico 100.

<resources> <item name="Id_For_ViewPager" type="id"/> </resources>

y setId (R.Id_For_ViewPager).

Consulte la fuente FragmentManager.java para obtener más detalles.

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

O vea esta página (en japonés). La idea original es de ella, en realidad, no de mí. http://y-anz-m.blogspot.jp/2012/04/androidfragment-viewpager-id.html



Jords, creo que puedes usar FragmentStatePagerAdapter lugar de FragmentPageAdapter . Eliminará fragmentos por ti.

PD. Perdón por usar la respuesta en lugar de comentar, pero mi reputación es muy baja.


Me encontré con este mismo problema. Tenía un Fragment que necesitaba alojar un ViewPager de Fragments . Cuando ViewPagerFragment otro Fragment encima de mi ViewPagerFragment , y luego ViewPagerFragment , obtendría una IllegalStateException . Después de verificar los registros (al apilar un nuevo Fragment ), encontré que mi ViewPagerFragment pasaría por sus métodos de ciclo de vida para detener y destruir, sin embargo, sus Fragments ViewPager en el ViewPager permanecerían en onResume . Me di cuenta de que los Fragments ViewPagerFragment deberían ser gestionados por FragmentManager para ViewPagerFragment , no como FragmentManager de la Activity .

Entiendo en ese momento, las respuestas anteriores fueron para evitar las limitaciones de los Fragments no pueden tener Fragments niños. Sin embargo, ahora que la última biblioteca de soporte tiene soporte para el anidamiento de Fragment , ya no es necesario ViewPager el adaptador para su ViewPager , y solo es necesario pasar a getChildFragmentManager() . Esto ha estado funcionando perfectamente para mí hasta ahora.

@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; }


Me he enfrentado a este problema al intentar inicializar el adaptador viewPager en el TabIndicator en ViewCreated. Después de leer sobre esto en línea, me di cuenta de que esto podría ser solo porque el fragmento aún no se había agregado a la actividad. Así que moví el código de inicialización a onStart () del fragmento, esto debería resolver su problema. Pero no para mí todavía estaba recibiendo el mismo problema otra vez.

Pero eso fue porque en mi código estaba intentando omitir la ejecución asincrónica normal de la tarea pendiente al llamar explícitamente a executePendingTransactions (), después de bloquear que todo funcionó bien


Usando esta brillante publicación de Thomas Amssler: http://tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part-ii.html

Iv''e creó un adaptador que se puede usar para crear todo tipo de fragmentos. El adaptador en sí se ve así:

public abstract class EmbeddedAdapter extends FragmentStatePagerAdapter { private SparseArray<WeakReference<Fragment>> mPageReferenceMap = new SparseArray<WeakReference<Fragment>>(); private ArrayList<String> mTabTitles; public abstract Fragment initFragment(int position); public EmbeddedAdapter(FragmentManager fm, ArrayList<String> tabTitles) { super(fm); mTabTitles = tabTitles; } @Override public Object instantiateItem(ViewGroup viewGroup, int position) { mPageReferenceMap.put(Integer.valueOf(position), new WeakReference<Fragment>(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<Fragment> weakReference = mPageReferenceMap.get(key); if (null != weakReference) { return (Fragment) weakReference.get(); } else { return null; } } @Override public int getItemPosition(Object object) { return POSITION_NONE; }

}

Para usar el adaptador, deberá hacer lo siguiente:

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); mPagerTabStrip.setVisibility(View.VISIBLE); mAdapter.notifyDataSetChanged(); } }); }

Tenga en cuenta que todos los fragmentos usan:

setRetainInstance(true);


usa AsyncTask para configurar el adaptador para viewPager. Esto funciona para mi. El asyncTask es hacer que el fragmento original complete su transición. y luego procedemos con los fragmentos de viewPager, básicamente para evitar la recursión.

@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); } }


Handler.post() para configurar el adaptador fuera de la transacción de fragmento original:

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