java android android-fragments android-viewpager illegalstateexception

java - IllegalStateException:<MyFragment> no se encuentra actualmente en el FragmentManager



android android-fragments (12)

Sé que suena como un duplicado de FragmentStatePagerAdapter IllegalStateException: <MyFragment> no está actualmente en el FragmentManager pero su solución no es relevante para mi caso.

Estoy recibiendo el siguiente bloqueo muy rara vez:

java.lang.RuntimeException: no se puede pausar la actividad {MyActivity}:

...

Causado por: java.lang.IllegalStateException: Fragment MyFragment {40648258 id = 0x7f070051} no se encuentra actualmente en el FragmentManager en android.support.v4.app.FragmentManagerImpl.putFragment (MT: 516) en android.support.v4.app.FragmentStatePagerAdapter .saveState (MT: 185) en android.support.v4.view.ViewPager.onSaveInstanceState (MT: 881)

...

en android.view.View.saveHierarchyState (View.java:6238) en com.android.internal.policy.impl.PhoneWindow.saveHierarchyState (PhoneWindow.java:1522) en android.app.Activity.onSaveInstanceState (Activity.java:1138 ) en android.support.v4.app.FragmentActivity.onSaveInstanceState (MT: 480) en MyActivity.onSaveInstanceState (MT: 336)

Parece que este es el código extraño que no puedo entender de FragmentStatePagerAdapter :

for (int i=0; i<mFragments.size(); i++) { Fragment f = mFragments.get(i); if (f != null) { if (state == null) { state = new Bundle(); } String key = "f" + i; mFragmentManager.putFragment(state, key, f); } }

Parece que el adaptador obtiene mi Fragment de mFragments pero no puede agregar su estado a FragmentManager .

No pude encontrar ninguna forma de recrear esto en mis dispositivos de prueba, solo lo recibí de algunos usuarios.

Estoy usando el paquete de soporte v4.

¿Alguna ayuda? Gracias.


¿Estás llamando a FragmentStatePagerAdapter.instantiateItem () desde tu propio código? En general, ViewPager debe ser el único cliente que llama a este método, sin embargo, es fácil encontrar soluciones para otras limitaciones que dependen de este método.

Debido a la forma en que funciona FragmentStatePagerAdapter , supongo que el adaptador ha instanciado el Fragmento, lo ha agregado a su colección interna de Fragmentos, e incluso comenzó una transacción para agregar ese Fragment al FragmentManager, pero esa transacción de fragmento no se ha confirmado ni ejecutado . Esto es exactamente lo que hace instantiateItem() cuando aún no ha instanciado el Fragment solicitado.

Otro método, FragmentStatePagerAdapter.finishUpdate() es responsable de confirmar la transacción y de ejecutar las transacciones pendientes. Se debe llamar a finishUpdate () después de instantiateItem () o de lo contrario el Fragment no se puede agregar al FragmentManager.

Pruebe algo como esto:

// Get the current Fragment presented by the ViewPager. pagerAdapter.startUpdate(viewPager); Fragment fragment = pagerAdapter.instantiateItem(viewPager, viewPager.getCurrentItem()); pagerAdapter.finishUpdate(viewPager); return fragment;

startUpdate () tiene una implementación vacía a partir del nivel 19 de la API.


Escribir en el método Activity onCreate ():

pager = (ViewPager) findViewById(R.id.pager); adapter = new SwipePagerAdapter(getSupportFragmentManager()); pageOneFragment = new PageOneFragment(); adapter.addFragment(pageOneFragment);

Código de adaptador:

public class SwipePagerAdapter extends FragmentStatePagerAdapter { private final ArrayList<Fragment> mFragments = new ArrayList<Fragment>(); public SwipePagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return mFragments.get(position); } @Override public int getCount() { return mFragments.size(); } public void addFragment(Fragment fragment) { mFragments.add(fragment); notifyDataSetChanged(); } @Override public void destroyItem(ViewGroup container, int position, Object object) { super.destroyItem(container, position, object); } @Override public CharSequence getPageTitle(int position) { return super.getPageTitle(position); }}


Esto puede suceder cuando se establece un FragmentStatePagerAdapter en un ViewPager, con los Fragmentos llenados, pero aún no agregados al FragmentManager debido a la pausa de la Actividad antes de que ocurra el diseño para el ViewPager. Esto se soluciona de manera confiable al iniciar otra Actividad desde onCreate, con el Adaptador también configurado en Crear. En esa situación, es mejor esperar para configurar el Adaptador y, en su lugar, configurarlo en ActivityResult. Consulte este problema: https://code.google.com/p/android/issues/detail?id=77285

También envié un parche para verificar que el Fragmento se haya agregado antes de intentar guardar el estado.


He encontrado la excepción exacta.

En mi caso, tengo varios fragmentos gestionados por FragmentPagerStateAdapter, pero a veces el fragmento cambiará de posición.

Sobreescribo getItemPosition () y devuelvo la nueva posición y llamo notifyDataSetChanged () para actualizar ViewPager. Todo funciona bien, pero a veces, cuando dejo ViewPager, se produce el bloqueo.

Después de varias horas investigando, descubrí que hay un error en FragmentPagerStateAdapter.

El adaptador no solo almacena estados en caché, sino que también almacena en caché los fragmentos que considera "activos"

private ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>(); private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();

Pero no verifica si la posición de los fragmentos se ha invalidado o movido.

Así es como se obtiene esta excepción:

1.Tengo A, B, C tres Fragmentos en ViewPager y Adaptador.

2. Cambié la posición a B, A, C en el adaptador y llamé notifyDataSetChanged ().

3.ViewPager rediseña el fragmento por orden nuevo. Pero la memoria caché mFragments sigue siendo {A, B, C}

4.Deslice unas pocas páginas, ViewPager pedirá adaptador para destruir el primer Fragmento. entonces el fragmento B, en lugar de A, se establece en nulo en la memoria caché. Ahora los mFragmentos son {nulo, A, C}.

5.Deje ViewPager y se activa onSaveInstanceState. todos los fragmentos en mFragmentos se consideran activos y se llama a putFragment () hasta que FragmentManagerImpl encuentre A no en él y genere una Excepción.

Así que aquí está mi solución no tan amable:

1. Copie todo el código fuente de FragmentPagerStateAdapter.

2. Suprima el método notifyDataSetChanged () para reorganizar las cachés de la siguiente manera.

@Override public void notifyDataSetChanged() { List<Fragment> oldFragments = new ArrayList<>(mFragments); List<Fragment.SavedState> oldStates = new ArrayList<>(mSavedState); for (int i = 0; i < getCount(); i++) { if (i < mFragments.size()) { Fragment f = mFragments.get(i); if (f != null) { int newPosition = getItemPosition(f); if (newPosition == POSITION_UNCHANGED || newPosition == i) { } else if (newPosition == POSITION_NONE) { if (i < mSavedState.size()) { mSavedState.set(i, null); } mFragments.set(i, null); } else { while (i >= mFragments.size()) { mFragments.add(null); } if (oldStates.size() > i) { mSavedState.set(newPosition, oldStates.get(i)); } mFragments.set(newPosition, oldFragments.get(i)); } } else { /* * No Fragment but that''s possible there''s savedState and position has * changed. */ } } } super.notifyDataSetChanged(); }

Espero que eso funcione para algunos de ustedes!


Intenta usar

use fragmentTransaction.add()



Puede intentar usar mFragmentManager.add();


Si su ViewPager se encuentra dentro de un fragmento (no una actividad):

mViewPager.setAdapter(new MyFragmentStatePagerAdapter(get Child FragmentManager()));



Utilice getChildFragmentManager() lugar de getFragmentManager() si tiene una jerarquía de fragmentos. p.ej. si tienes fragmentos buscapersonas


Verifique dos onSaveInstanceState si ha implementado onSaveInstanceState y onRestoreInstanceState en su actividad, y verifique que estén guardando y cargando correctamente el estado de sus fragmentos.


FragmentStatePagerAdapter es una horrible pieza de código plagada de errores reconocidos o no por Google, por lo que utilizo este código para solucionar este bloqueo en particular:

@Override public void destroyItem(ViewGroup container, int position, Object object) { // Yet another bug in FragmentStatePagerAdapter that destroyItem is called on fragment that hasnt been added. Need to catch try { super.destroyItem(container, position, object); } catch (IllegalStateException ex) { ex.printStackTrace(); } }