Usuario
Quiero entender esta excepción para implementar una solución adecuada.
Hay un ViewPager y usa un FragmentStatePagerAdapter para instanciar 2 fragmentos a través de getItem y MyFragmentClass.newInstance(...)
.
El getItem del adaptador se ve así:
@Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch(position) {
case 0:
fragment = MyFragment2.newInstance(par1);
break;
case 1:
fragment = MyFragment2.newInstance(par2, par3);
break;
}
return fragment;
}
Problema:
Cuando la actividad se destruye y se vuelve a crear, el adaptador se instancia nuevamente, los fragmentos se crean nuevamente con MyFragmentClass.newInstance(...)
… pero luego en esta línea:
pager.setAdapter(adapter);
Obtengo la excepción mencionada.
Busqué en la fuente donde se lanza la excepción, es esto:
@Override
public Fragment getFragment(Bundle bundle, String key) {
int index = bundle.getInt(key, -1);
if (index == -1) {
return null;
}
if (index >= mActive.size()) {
throw new IllegalStateException("Fragement no longer exists for key "
+ key + ": index " + index);
}
Fragment f = mActive.get(index);
if (f == null) {
throw new IllegalStateException("Fragement no longer exists for key "
+ key + ": index " + index);
}
return f;
}
Entonces se pasa un paquete allí, con algún estado que hace referencia a mis fragmentos antiguos, pero esto no corresponde al estado actual (mActive
), y se lanza la excepción.
No entiendo cuál es la idea detrás de esto, o de qué manera se supone que debo instanciar los fragmentos.
Intenté un truco que obtuve de otro contexto:
pager.setOffscreenPageLimit(1);
Para evitar que los fragmentos se destruyan cuando están fuera de pantalla (en el caso del visor de 2 páginas, aunque no sé si funciona bien con el adaptador de estado). Pero no parece estar relacionado, al menos, no ayuda, sigue teniendo la misma excepción.
Al detectar la excepción, las páginas quedan en blanco.
mikelis kaneps
Esto podría ayudar –
@Override
public Parcelable saveState() {
return null;
}
Agregue la línea de arriba en FragmentStatePagerAdapter
.
-
Esto funciona perfectamente para tratar con un adaptador de megafonía en la pila trasera. ¡Gracias!
–Andy H.
10 de agosto de 2015 a las 20:22
-
si estas evitando
saveState()
ya no necesitas usarFragmentStatePagerAdapter
. Entonces solo tienes que usarFragmentPagerAdapter
para trabajar– Lennon Spirlandelli
29/01/2016 a las 19:01
-
@Nishad, ¿qué no es cierto?
– Lennon Spirlandelli
17 de febrero de 2016 a las 18:56
-
evitando
saveState()
porFragmentStatePagerAdapter
no es equivalente a usarFragmentPagerAdapter
.FragmentStatePagerAdapter
destruye los objetos fragmentados cuando no están en usoFragmentPagerAdapter
no es. Al evitar saveState() estamos pidiendoFragmentStatePagerAdapter
para destruir fragmentos sin salvar el estado.– Nishad
18 de febrero de 2016 a las 7:07
-
@Lennon
FragmentPagerAdapter
no usasaveState()
porque todo el fragmento se retiene en la memoria. Si quieres evitar ese comportamiento que utilizasFragmentStatePagerAdapter
que solo guarda el estado. Si no desea guardar nada en absoluto, utiliceFragmentStatepagerAdapter
sin estado de ahorro; automáticamente no guarda elFragment
en memoria.– Andrew Orobator
18 de enero de 2017 a las 19:01
Si no desea que los fragmentos se recuperen cuando están fuera de la pantalla, debe usar FragmentPagerAdapter
y no FragmentStatePagerAdapter
.
-
¿Cuál es la diferencia en esta situación?
– TootsieRockNRoll
28 de enero de 2014 a las 9:26
-
FragmentPagerAdapter
carga cada fragmento en la memoria a medida que se visita.FragmentStatePagerAdapter
libera su referencia a fragmentos una vez que han pasado eloffscreenPageLimit
parámetro.– un poco
28 de enero de 2014 a las 10:22
-
Entonces, si establecemos un límite de página fuera de la pantalla, ¿ya no sería un problema? (Para el
FragmentStatePagerAdapter
)– TootsieRockNRoll
28 de enero de 2014 a las 10:25
-
No, el cartel original estaba haciendo algo más mal, como configurar incorrectamente la cantidad de elementos.
– un poco
28 de enero de 2014 a las 10:38
vicky
Detalle del problema
De forma predeterminada, FragmentStatePagerAdapter guardará y restaurará el estado de ViewPager. Mientras se restaura si la instancia del fragmento se elimina debido a algún motivo, FragmentManger generará esta excepción.
Solución:
Para solucionar esto, es necesario anular el método restoreState en nuestro FragmentStatePagerAdapter y colocar el bloque try catch. Evitará el bloqueo y también conservará el estado de fragmento del visor para el caso normal.
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
try {
super.restoreState(state, loader);
} catch (Exception e) {
Log.e("TAG", "Error Restore State of Fragment : " + e.getMessage(), e);
}
}
Nota: Podemos usar FragmentPagerAdapter o Override saveState() y devolver nulo también soluciona este problema, pero el visualizador no conservará su estado en el caso normal.
-
Gracias @Vicky, funciona de maravilla, esta debe marcarse como la respuesta correcta.
– Muhammad Faizán
30 de noviembre de 2019 a las 6:39
-
no se puede anular, se establece como final 🙁
– Daniyal Javaid
20 abr 2021 a las 23:02
si está utilizando ViewPager2, utilice este método en el objeto ViewPager2
viewPager2.setSaveEnabled(false);
yi wang
Tuve problemas con este problema durante todo el día, pero ahora encontré la solución.
private ViewPager _mViewPager;
_mViewPager.setOffscreenPageLimit(5);
//5 is how much page you have.
setOffscreenPageLimit
Establezca el número de páginas que deben conservarse a ambos lados de la página actual en la jerarquía de vistas en estado inactivo. Las páginas que superen este límite se recrearán desde el adaptador cuando sea necesario.
-
esto usa una tonelada de memoria… ahorra la molestia de no guardar el estado y todo eso… pero esto es malo a largo plazo cuando hay una tonelada de datos
– Kushán
1 de febrero de 2017 a las 21:22
Ilya Gazman
Use Ciclo de vida de actividad en lugar de Fragmento.
public class MyAdapter extends FragmentStateAdapter {
public MyAdapter (@NonNull Fragment fragment) {
super(fragment.getFragmentManager(), fragment.getActivity().getLifecycle());
}
}
O como otros mencionaron deshabilitar el ViewPager2
guardar Estado.
- en Diseño:
android:saveEnabled="false"
- en codigo:
viewPager.setSaveEnabled(false);
viewPager.setSaveFromParentEnabled(false);
-
esto usa una tonelada de memoria… ahorra la molestia de no guardar el estado y todo eso… pero esto es malo a largo plazo cuando hay una tonelada de datos
– Kushán
1 de febrero de 2017 a las 21:22
任非凡
Muy bueno ! Ya que se repite pager.setAdapter(adapter);
cuando llame restoreState
Causa excepción:
Fragment no longer exists for key f0: index 0
podemos liberar fragmento RootView
public void onDestroyView() {
super.onDestroyView();
if (isRecyclerRootViewAlways()) {
mRootView = null;//<--
}
mMyFragmentLifecycle.onFragmentDestroyView(this);
}
¿Encontraste una solución funcional para tu problema?
– guardarpoblación
26 de noviembre de 2014 a las 18:27
Encontraste alguna solución
– Stefan Rasmusson
17 de julio de 2015 a las 10:46
no recuerdo, lo siento 🙁
– Usuario
17 de julio de 2015 a las 10:58
La pregunta fue hecha hace 2 años. Hoy en día, se utilizan AppcompatActivity y support fragment. Utilice setRetianInstance(verdadero); y recuerde recrear el adaptador con elementos existentes en la orientación. Si no vuelve a crear el adaptador, intentará usar el contexto desechado, lo que provocará el bloqueo.
– HBB20
26/10/2015 a las 10:37
El mismo tema se trata en el hilo. code.google.com/p/android/issues/detail?id=54520
– Conocer
31 de marzo de 2016 a las 12:28