IllegalStateException: no se puede realizar esta acción después de onSaveInstanceState con ViewPager

Resuelto nhaarman asked hace 54 años • 37 respuestas

Recibo informes de usuarios de mi aplicación en el mercado, lo que genera la siguiente excepción:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1109)
at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:399)
at android.app.Activity.onBackPressed(Activity.java:2066)
at android.app.Activity.onKeyUp(Activity.java:2044)
at android.view.KeyEvent.dispatch(KeyEvent.java:2529)
at android.app.Activity.dispatchKeyEvent(Activity.java:2274)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1855)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1277)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.widget.TabHost.dispatchKeyEvent(TabHost.java:297)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1855)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1277)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewRoot.deliverKeyEventPostIme(ViewRoot.java:2880)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2853)
at android.view.ViewRoot.handleMessage(ViewRoot.java:2028)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4028)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
at dalvik.system.NativeStart.main(Native Method)

Aparentemente tiene algo que ver con un FragmentManager, que no uso. Stacktrace no muestra ninguna de mis clases, por lo que no tengo idea de dónde ocurre esta excepción y cómo evitarla.

Para que conste: tengo un tabhost y en cada pestaña hay un grupo de actividades que cambia entre actividades.

nhaarman avatar Jan 01 '70 08:01 nhaarman
Aceptado

Por favor revisa mi respuesta aquí . Básicamente solo tenía que:

@Override
protected void onSaveInstanceState(Bundle outState) {
    //No call for super(). Bug on API Level > 11.
}

No realice la llamada super()al saveInstanceStatemétodo. Esto estaba arruinando las cosas...

Este es un error conocido en el paquete de soporte.

Si necesita guardar la instancia y agregar algo, outState Bundlepuede usar lo siguiente:

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
    super.onSaveInstanceState(outState);
}

Al final, la solución adecuada fue (como se ve en los comentarios) utilizar:

transaction.commitAllowingStateLoss();

al agregar o realizar el FragmentTransactionque estaba causando el Exception.

Ovidiu Latcu avatar Apr 21 '2012 17:04 Ovidiu Latcu

Hay muchos problemas relacionados con un mensaje de error similar. Verifique la segunda línea de este seguimiento de pila en particular. Esta excepción está específicamente relacionada con la llamada a FragmentManagerImpl.popBackStackImmediate.

Esta llamada a método, como popBackStack, siempre fallará IllegalStateExceptionsi el estado de la sesión ya se ha guardado. Comprueba la fuente. No hay nada que pueda hacer para evitar que se lance esta excepción.

  • Eliminar la llamada a super.onSaveInstanceStateno ayudará.
  • Crear el Fragmento commitAllowingStateLossno ayudará.

Así es como observé el problema:

  • Hay un formulario con un botón de enviar.
  • Cuando se hace clic en el botón, se crea un cuadro de diálogo y se inicia un proceso asíncrono.
  • El usuario hace clic en la tecla de inicio antes de que finalice el proceso: onSaveInstanceStatese le llama.
  • El proceso se completa, se realiza una devolución de llamada y popBackStackImmediatese intenta.
  • IllegalStateExceptiones aventado.

Esto es lo que hice para resolverlo:

Como no es posible evitarlo IllegalStateExceptionen la devolución de llamada, cógelo e ignóralo.

try {
    activity.getSupportFragmentManager().popBackStackImmediate(name);
} catch (IllegalStateException ignored) {
    // There's no way to avoid getting this if saveInstanceState has already been called.
}

Esto es suficiente para evitar que la aplicación falle. Pero ahora el usuario restaurará la aplicación y verá que el botón que pensó que había presionado no ha sido presionado en absoluto (cree). ¡El fragmento del formulario todavía se muestra!

Para solucionar este problema, cuando se cree el cuadro de diálogo, establezca algún estado para indicar que el proceso ha comenzado.

progressDialog.show(fragmentManager, TAG);
submitPressed = true;

Y guarde este estado en el paquete.

@Override
public void onSaveInstanceState(Bundle outState) {
    ...
    outState.putBoolean(SUBMIT_PRESSED, submitPressed);
}

No olvides volver a cargarlo enonViewCreated

Luego, al reanudar, revierta los fragmentos si se intentó enviar previamente. Esto evita que el usuario vuelva a lo que parece un formulario no enviado.

@Override
public void onResume() {
    super.onResume();
    if (submitPressed) {
        // no need to try-catch this, because we are not in a callback
        activity.getSupportFragmentManager().popBackStackImmediate(name);
        submitPressed = false;
    }
}
Synesso avatar Jan 09 '2015 04:01 Synesso

Compruebe si la actividad isFinishing()antes de mostrar el fragmento y preste atención commitAllowingStateLoss().

Ejemplo:

if(!isFinishing()) {
FragmentManager fm = getSupportFragmentManager();
            FragmentTransaction ft = fm.beginTransaction();
            DummyFragment dummyFragment = DummyFragment.newInstance();
            ft.add(R.id.dummy_fragment_layout, dummyFragment);
            ft.commitAllowingStateLoss();
}
Naskov avatar Mar 04 '2015 01:03 Naskov