Recibo informes de usuarios de mi aplicación en el mercado, entregando 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. El stacktrace no muestra ninguna de mis propias clases, por lo que no tengo idea de dónde ocurre esta excepción y cómo prevenirla.
Para el registro: tengo un tabhost, y en cada pestaña hay un ActivityGroup que cambia entre Actividades.
FragmentManager
, Honeycomb ciertamente lo está. ¿Está sucediendo esto en tabletas Honeycomb reales? ¿O podría ser que alguien está ejecutando un Honeycomb pirateado en un teléfono o algo así y es esa edición pirateada la que tiene dificultades?Respuestas:
Por favor revisa mi respuesta aquí . Básicamente solo tenía que:
No haga la llamada a
super()
lasaveInstanceState
método. Esto estaba arruinando las cosas ...Este es un error conocido en el paquete de soporte.
Si necesita guardar la instancia y agregarle algo
outState
Bundle
, puede usar lo siguiente:Al final, la solución adecuada fue (como se ve en los comentarios) usar:
al agregar o realizar lo
FragmentTransaction
que estaba causando elException
.fuente
popBackStackImmediate
, inmediatamente falla si el estado se ha guardado. Anteriormente agregar el fragmento concommitAllowingStateLoss
no juega ningún papel. Mi prueba muestra que esto es cierto. No tiene ningún efecto sobre esta excepción específica. Lo que necesitamos es unpopBackStackImmediateAllowingStateLoss
método.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 al método, como
popBackStack
, siempre fallaráIllegalStateException
si el estado de la sesión ya se ha guardado. Verifica la fuente. No hay nada que pueda hacer para evitar que se lance esta excepción.super.onSaveInstanceState
no ayudará.commitAllowingStateLoss
no ayudará.Así es como observé el problema:
onSaveInstanceState
llama al usuario que hace clic en la tecla de inicio antes de que finalice el proceso .popBackStackImmediate
se intenta.IllegalStateException
es aventado.Esto es lo que hice para resolverlo:
Como no es posible evitar
IllegalStateException
la devolución de llamada, cógela e ignórala.Esto es suficiente para evitar que la aplicación se bloquee. Pero ahora el usuario restaurará la aplicación y verá que el botón que creyeron haber presionado no se ha presionado en absoluto (piensan). ¡El fragmento de formulario todavía se muestra!
Para solucionar esto, cuando se crea el cuadro de diálogo, haga un estado para indicar que el proceso ha comenzado.
Y guarde este estado en el paquete.
No olvides cargarlo nuevamente en
onViewCreated
Luego, al reanudar, revierta los fragmentos si se intentó enviar previamente. Esto evita que el usuario regrese a lo que parece un formulario no enviado.
fuente
popBackStackImmediate
fue llamado por el propio Android?Compruebe si la actividad
isFinishing()
antes de mostrar el fragmento y preste atencióncommitAllowingStateLoss()
.Ejemplo:
fuente
DialogFragment
. Ver stackoverflow.com/questions/15729138/… para otras buenas soluciones, stackoverflow.com/a/41813953/2914140 me ayudó.Es octubre de 2017, y Google crea la Biblioteca de soporte de Android con el nuevo componente llamado ciclo de vida. Proporciona una idea nueva para este problema 'No se puede realizar esta acción después de onSaveInstanceState'.
En breve:
Versión más larga con explicar:
¿Por qué sale este problema?
Es porque está intentando utilizar
FragmentManager
su actividad (¿qué va a contener su fragmento, supongo?) Para confirmar una transacción para su fragmento. Por lo general, esto parecería que está tratando de hacer alguna transacción para un fragmento próximo, mientras tanto, la actividad del host ya llama alsavedInstanceState
método (el usuario puede tocar el botón de inicio para que la actividad llameonStop()
, en mi caso es la razón)Por lo general, este problema no debería suceder; siempre intentamos cargar el fragmento en la actividad desde el principio, como si el
onCreate()
método fuera el lugar perfecto para esto. Pero a veces esto sucede , especialmente cuando no puede decidir qué fragmento cargará en esa actividad, o si está tratando de cargar un fragmento desde unAsyncTask
bloque (o cualquier cosa tomará un poco de tiempo). El tiempo, antes de que la transacción del fragmento realmente ocurra, pero después delonCreate()
método de la actividad , el usuario puede hacer cualquier cosa. Si el usuario presiona el botón de inicio, que activa elonSavedInstanceState()
método de la actividad , se produciría uncan not perform this action
bloqueo.Si alguien quiere ver más profundamente en este tema, sugiero que miren este blog posterior . Se ve profundamente dentro de la capa de código fuente y explica mucho al respecto. Además, da la razón por la que no debería usar el
commitAllowingStateLoss()
método para solucionar este bloqueo (créame, no ofrece nada bueno para su código)¿Cómo arreglar esto?
¿Debo usar el
commitAllowingStateLoss()
método para cargar fragmentos? No, no deberías ;¿Debo anular el
onSaveInstanceState
método, ignorar elsuper
método dentro de él? No, no deberías ;¿Debo usar la
isFinishing
actividad mágica interna para verificar si la actividad del host está en el momento adecuado para una transacción fragmentada? Sí, esto parece la forma correcta de hacerlo.Eche un vistazo a lo que puede hacer el componente Lifecycle .
Básicamente, Google realiza algunas implementaciones dentro de la
AppCompatActivity
clase (y varias otras clases base que debe usar en su proyecto), lo que facilita la determinación del estado actual del ciclo de vida . Eche un vistazo a nuestro problema: ¿por qué sucedería este problema? Es porque hacemos algo en el momento equivocado. Así que tratamos de no hacerlo, y este problema desaparecerá.Codifico un poco para mi propio proyecto, esto es lo que hago usando
LifeCycle
. Codifico en Kotlin.Como muestro arriba. Comprobaré el estado del ciclo de vida de la actividad del host. Con el componente Lifecycle dentro de la biblioteca de soporte, esto podría ser más específico. El código
lifecyclecurrentState.isAtLeast(Lifecycle.State.RESUMED)
significa, si el estado actual es al menosonResume
, ¿no más tarde? Lo que asegura que mi método no se ejecutará durante algún otro estado de vida (comoonStop
).¿Ya está todo hecho?
Por supuesto no. El código que he mostrado muestra una nueva forma de evitar que la aplicación se bloquee. Pero si va al estado de
onStop
, esa línea de código no hará cosas y, por lo tanto, no mostrará nada en la pantalla. Cuando los usuarios vuelvan a la aplicación, verán una pantalla vacía, esa es la actividad de host vacía que no muestra ningún fragmento. Es una mala experiencia (sí, un poco mejor que un accidente).Así que aquí desearía que pudiera haber algo más agradable: la aplicación no se bloqueará si se trata de un estado de vida posterior
onResume
, el método de transacción es consciente del estado de vida; Además, la actividad intentará continuar con esa acción de transacción fragmentada, después de que el usuario regrese a nuestra aplicación.Agrego algo más a este método:
Mantengo una lista dentro de esta
dispatcher
clase, para almacenar esos fragmentos no tengo la oportunidad de finalizar la acción de la transacción. Y cuando el usuario regrese de la pantalla de inicio y descubra que todavía hay un fragmento esperando a ser lanzado, irá alresume()
método bajo la@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
anotación. Ahora creo que debería funcionar como esperaba.fuente
FragmentDispatcher
utilizar una lista para almacenar fragmentos pendientes si solo se restaurará un fragmento?Aquí hay una solución diferente a este problema.
Al usar una variable miembro privada, puede establecer los datos devueltos como una intención que luego se puede procesar después de super.onResume ();
Al igual que:
fuente
super.onActivityResult()
.Solución corta y funcional:
Siga pasos simples
Pasos
Paso 1: anular el
onSaveInstanceState
estado en el fragmento respectivo. Y elimine el súper método.Paso 2: uso
fragmentTransaction.commitAllowingStateLoss( );
en lugar de
fragmentTransaction.commit( );
fragmentar operaciones.fuente
CUIDADO , el uso
transaction.commitAllowingStateLoss()
podría resultar en una mala experiencia para el usuario. Para obtener más información sobre por qué se produce esta excepción, consulte esta publicación .fuente
Encontré una solución sucia para este tipo de problema. Si aún desea conservar su
ActivityGroups
por cualquier razón (tenía razones de limitación de tiempo), simplemente implementeen su
Activity
y hacer algo deback
código allí. incluso si no existe tal método en dispositivos más antiguos, este método es llamado por los más nuevos.fuente
No use commitAllowingStateLoss (), solo debe usarse para casos en los que está bien que el estado de la IU cambie inesperadamente en el usuario.
https://developer.android.com/reference/android/app/FragmentTransaction.html#commitAllowingStateLoss ()
Si la transacción ocurre en ChildFragmentManager de parentFragment, use parentFragment.isResume () afuera para verificar en su lugar.
fuente
Tuve un problema similar, el escenario era así:
El método onCreate de la actividad era así:
La excepción se produjo porque cuando la configuración cambia (dispositivo girado), se crea la actividad, el fragmento principal se recupera del historial del administrador de fragmentos y al mismo tiempo el fragmento ya tiene una referencia ANTIGUA a la actividad destruida
cambiando la implementación a esto resolvió el problema:
debe configurar sus oyentes cada vez que se crea la actividad para evitar la situación en la que los fragmentos tienen referencias a instancias destruidas de la actividad.
fuente
Si hereda de
FragmentActivity
, debe llamar a la superclase enonActivityResult()
:Si no hace esto e intenta mostrar un cuadro de diálogo de fragmento en ese método, puede obtener OP
IllegalStateException
. (Para ser honesto, no entiendo por qué la súper llamada soluciona el problema.onActivityResult()
Se llama antesonResume()
, por lo que aún no se debe permitir que muestre un cuadro de diálogo de fragmento).fuente
Recibí esta excepción cuando presioné el botón Atrás para cancelar el selector de intención en mi actividad de fragmento de mapa. Resolví esto reemplazando el código de onResume (donde estaba inicializando el fragmento) por onstart () y la aplicación funciona bien. Espero que ayude.
fuente
Creo que usar
transaction.commitAllowingStateLoss();
no es la mejor solución. Esta excepción se generará cuando la configuración de la actividad cambie yonSavedInstanceState()
se llame al fragmento y, posteriormente, su método de devolución de llamada asincrónica intente confirmar el fragmento.Una solución simple podría ser verificar si la actividad está cambiando la configuración o no
por ejemplo, verificar
isChangingConfigurations()
es decir
if(!isChangingConfigurations()) { //commit transaction. }
Mira este enlace también
fuente
Posiblemente la solución más sencilla y sencilla que encontré en mi caso fue evitar sacar el fragmento ofensivo de la pila en respuesta al resultado de la actividad. Entonces cambiando esta llamada en mi
onActivityResult()
:a esto:
ayudó en mi caso.
fuente
Si está haciendo alguna FragmentTransaction en onActivityResult, lo que puede hacer puede establecer un valor booleano dentro de onActivityResult, luego en onResume puede hacer su FragmentTransaction en función del valor booleano. Por favor, consulte el código a continuación.
fuente
Cortesía: Solución para IllegalStateException
Este problema me había molestado durante mucho tiempo, pero afortunadamente encontré una solución concreta. Una explicación detallada de esto está aquí .
El uso de commitAllowStateloss () podría evitar esta excepción, pero provocaría irregularidades en la interfaz de usuario. Hasta ahora hemos entendido que se encuentra IllegalStateException cuando intentamos confirmar un fragmento después de que se pierde el estado de Actividad, por lo que deberíamos retrasar la transacción hasta que se restablezca el estado Se puede hacer simplemente así
Declara dos variables booleanas privadas
Ahora en onPostResume () y onPause establecemos y desarmamos nuestra variable booleana isTransactionSafe. La idea es marcar la trasnsacción como segura solo cuando la actividad está en primer plano para que no haya posibilidad de pérdida de estado.
-Lo que hemos hecho hasta ahora ahorrará desde IllegalStateException pero nuestras transacciones se perderán si se realizan después de que la actividad pase a segundo plano, algo así como commitAllowStateloss (). Para ayudar con eso tenemos la variable booleana isTransactionPending
fuente
¡Las transacciones de fragmentos no deben ejecutarse después
Activity.onStop()
! Verifique que no tenga ninguna devolución de llamada que pueda ejecutar la transacción despuésonStop()
. Es mejor arreglar la razón en lugar de tratar de evitar el problema con enfoques como.commitAllowingStateLoss()
fuente
A partir de la versión 24.0.0 de la biblioteca de soporte, puede llamar al
FragmentTransaction.commitNow()
método que confirma esta transacción sincrónicamente en lugar de llamarcommit()
seguido deexecutePendingTransactions()
. Como dice la documentación , este enfoque es aún mejor:fuente
Cada vez que intente cargar un fragmento en su actividad, asegúrese de que la actividad se reanude y no vaya a pausar el estado. En el estado de pausa, puede terminar perdiendo la operación de confirmación que se realiza.
Puede usar transacción.commitAllowingStateLoss () en lugar de transacción.commit () para cargar el fragmento
o
Cree un booleano y verifique si la actividad no se va a pausar
luego, al cargar la comprobación de fragmentos
fuente
Para evitar este problema, podemos usar el Componente de Arquitectura de Navegación , que se introdujo en Google I / O 2018. El Componente de Arquitectura de Navegación simplifica la implementación de la navegación en una aplicación de Android.
fuente
Con respecto a la gran respuesta de @Anthonyeef, aquí hay un código de muestra en Java:
fuente
Si tiene un bloqueo con el método popBackStack () o popBackStackImmediate (), intente fixt con:
Esto también funcionó para mí.
fuente
En mi caso, recibí este error en un método de anulación llamado onActivityResult. Después de excavar, acabo de darme cuenta de que tal vez tenía que llamar " super " antes.
Lo agregué y simplemente funcionó
Tal vez solo necesite agregar un 'super' en cualquier anulación que esté haciendo antes de su código.
fuente
Extensión Kotlin
Uso:
fuente
fragment: Fragment
? Sí, probé esta variante, pero en este caso se crearía un fragmento en todos los casos (incluso cuando fragmentManager == nulo, pero no encontré esta situación). Actualicé la respuesta y cambié nulo para etiquetaraddToBackStack()
.Este bloqueo se debe a que se ha cometido una FragmentTransaction después de que el ciclo de vida de la actividad propietaria ya se haya ejecutado enSaveInstanceState. Esto a menudo es causado por la confirmación de FragmentTransactions desde una devolución de llamada asincrónica. Consulte el recurso vinculado para más detalles.
Fragmento de transacciones y pérdida de actividad del estado
http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html
fuente
Agregue esto a su actividad
fuente
También he experimentado este problema y el problema ocurre cada vez que
FragmentActivity
se cambia el contexto de usted (por ejemplo, se cambia la orientación de la pantalla, etc.). Entonces, la mejor solución es actualizar el contexto desde tuFragmentActivity
.fuente
Terminé creando un fragmento base y haciendo que todos los fragmentos de mi aplicación lo extiendan
Luego, cuando trato de mostrar un fragmento que uso en
showAllowingStateLoss
lugar deshow
Me gusta esto:
Llegué a esta solución desde este PR: https://github.com/googlesamples/easypermissions/pull/170/files
fuente
Otra posible solución, que no estoy seguro si ayuda en todos los casos (origen aquí ):
fuente
Sé que hay una respuesta aceptada por @Ovidiu Latcu, pero después de un tiempo, el error aún persiste.
Crashlytics todavía me envía este extraño mensaje de error.
Sin embargo, ahora se produce un error solo en la versión 7+ (Nougat). Mi solución fue usar commitAllowingStateLoss () en lugar de commit () en fragmentTransaction.
Esta publicación es útil para commitAllowingStateLoss () y nunca más tuvo un problema de fragmentos.
Para resumir, la respuesta aceptada aquí podría funcionar en las versiones de Android pre Nougat.
Esto podría ahorrarle a alguien unas horas de búsqueda. felices codificaciones <3 aplausos
fuente