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.
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
De acuerdo con la documentación: https://developer.android.com/reference/android/app/Fragment.html#getChildFragmentManager()
Si desea administrar el fragmento de anidación, debe usar getChildFragmentManager
lugar de getFragmentManager
.
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);
}
});
}