Algunos usuarios están informando, si usan la acción rápida en la barra de notificaciones, están obteniendo un cierre forzado.
Muestro una acción rápida en la notificación que llama a la clase "TestDialog" . En la clase TestDialog después de presionar el botón "snooze", mostraré el SnoozeDialog.
private View.OnClickListener btnSnoozeOnClick() {
return new View.OnClickListener() {
public void onClick(View v) {
showSnoozeDialog();
}
};
}
private void showSnoozeDialog() {
FragmentManager fm = getSupportFragmentManager();
SnoozeDialog snoozeDialog = new SnoozeDialog();
snoozeDialog.show(fm, "snooze_dialog");
}
El error es *IllegalStateException: Can not perform this action after onSaveInstanceState*.
La línea de código donde se dispara la IllegarStateException es:
snoozeDialog.show(fm, "snooze_dialog");
La clase está ampliando "FragmentActivity" y la clase "SnoozeDialog" está ampliando "DialogFragment".
Aquí está el seguimiento de pila completo del error:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1327)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1338)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
at android.support.v4.app.DialogFragment.show(DialogFragment.java:127)
at com.test.testing.TestDialog.f(TestDialog.java:538)
at com.test.testing.TestDialog.e(TestDialog.java:524)
at com.test.testing.TestDialog.d(TestDialog.java:519)
at com.test.testing.g.onClick(TestDialog.java:648)
at android.view.View.performClick(View.java:3620)
at android.view.View$PerformClick.run(View.java:14292)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4507)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
at dalvik.system.NativeStart.main(Native Method)
No puedo reproducir este error, pero recibo muchos informes de errores.
¿Alguien puede ayudarme, cómo puedo solucionar este error?
Respuestas:
Este es un problema común . Resolvimos este problema anulando show () y manejando la excepción en la clase extendida DialogFragment
Tenga en cuenta que la aplicación de este método no alterará los campos internos de DialogFragment.class:
Esto puede dar lugar a resultados inesperados en algunos casos. Mejor use commitAllowingStateLoss () en lugar de commit ()
fuente
Eso significa que usted
commit()
(show()
en el caso de DialogFragment) fragmenta despuésonSaveInstanceState()
.Android guardará el estado de su fragmento en
onSaveInstanceState()
. Por lo tanto, sicommit()
fragmenta trasonSaveInstanceState()
fragmento, se perderá el estado.Como resultado, si la actividad se elimina y se vuelve a crear más tarde, el fragmento no se agregará a la actividad, lo cual es una mala experiencia para el usuario. Por eso Android no permite la pérdida de estado a toda costa.
La solución fácil es comprobar si el estado ya se ha guardado.
Nota: onResumeFragments () llamará cuando se reanuden los fragmentos.
fuente
ref: enlace
fuente
Después de unos días, quiero compartir mi solución cómo la arreglé, para mostrar DialogFragment, debe anular el
show()
método y llamarcommitAllowingStateLoss()
alTransaction
objeto. Aquí hay un ejemplo en Kotlin:fuente
DialogFragment
que podría cambiar esto a ser una función de extensión Kotlin con la firma siguiente:fun DialogFragment.showAllowingStateLoss(fragmentManager: FragmentManager, tag: String)
. Además, try-catch no es necesario ya que está llamando alcommitAllowingStateLoss()
método y no alcommit()
método.Si el cuadro de diálogo no es realmente importante (está bien no mostrarlo cuando la aplicación se cerró / ya no está a la vista), use:
Y abre tu diálogo (fragmento) solo cuando estemos ejecutando:
EDITAR, PROBABLEMENTE MEJOR SOLUCIÓN:
Donde se llama a onSaveInstanceState en el ciclo de vida es impredecible, creo que una mejor solución es verificar isSavedInstanceStateDone () de esta manera:
fuente
Me he encontrado con este problema durante años.
Internet está plagado de decenas (¿cientos? ¿Miles?) De discusiones sobre esto, y la confusión y la desinformación en ellas parecen abundantes.
Para empeorar la situación, y en el espíritu del cómic xkcd "14 estándares", estoy lanzando mi respuesta al ring.
El
cancelPendingInputEvents()
,commitAllowingStateLoss()
,catch (IllegalStateException e)
, y soluciones similares todos parecen atroz.Con suerte, lo siguiente muestra fácilmente cómo reproducir y solucionar el problema:
fuente
intente utilizar FragmentTransaction en lugar de FragmentManager. Creo que el siguiente código resolverá tu problema. Si no es así, por favor hágamelo saber.
EDITAR:
Transacción de fragmentos
Por favor, consulte este enlace. Creo que te resolverá dudas.
fuente
Usar los nuevos alcances del ciclo de vida de Activity-KTX es tan simple como el siguiente ejemplo de código:
Este método se puede llamar directamente después de onStop () y mostrará correctamente el diálogo una vez que se haya llamado a onResume () al regresar.
fuente
Muchas vistas publican eventos de alto nivel, como controladores de clics, en la cola de eventos para que se ejecuten en diferido. Entonces, el problema es que "onSaveInstanceState" ya ha sido llamado para la actividad, pero la cola de eventos contiene un "evento de clic" diferido. Por lo tanto, cuando este evento se envía a su controlador
y su código hace que
show
se lanza la IllegalStateException.La solución más simple es limpiar la cola de eventos, en
onSaveInstanceState
fuente
activity
yfragment
).Haga que su objeto de fragmento de diálogo sea global y llame a dispatsAllowingStateLoss () en el método onPause ()
No olvide asignar un valor en el fragmento y llamar a show () al hacer clic en el botón o donde sea.
fuente
Aunque no se menciona oficialmente en ninguna parte, me enfrenté a este problema un par de veces. En mi experiencia, hay algo mal en la biblioteca de compatibilidad que admite fragmentos en plataformas más antiguas que causa este problema. Puedes probar esto usando la API normal del administrador de fragmentos. Si nada funciona, puede usar el diálogo normal en lugar del fragmento de diálogo.
fuente
Utilice el método showAllowingStateLoss en lugar de show
Disfruta;)
fuente
StatelessDialogFragment
uno de mis paquetes. Gracias amigo. Lo probaré en producción pronto.usa este código
en vez de
fuente
He encontrado una solución elegante para este problema utilizando la reflexión. El problema de todas las soluciones anteriores es que los campos mDismissed y mShownByMe no cambian su estado.
Simplemente anule el método "mostrar" en su propio fragmento de diálogo de hoja inferior personalizado como la muestra a continuación (Kotlin)
fuente
La siguiente implementación se puede utilizar para resolver el problema de realizar cambios de estado de forma segura durante el
Activity
ciclo de vida, en particular para mostrar diálogos: si el estado de la instancia ya se ha guardado (por ejemplo, debido a un cambio de configuración), los pospone hasta que el estado reanudado haya realizado.Luego, usando una clase como esta:
Puede mostrar cuadros de diálogo de forma segura sin preocuparse por el estado de la aplicación:
y luego llame
TestDialog.show(this)
desde dentro de suXAppCompatActivity
.Si desea crear una clase de diálogo más genérica con parámetros, puede guardarlos
Bundle
con los argumentos delshow()
método y recuperarlos congetArguments()
inonCreateDialog()
.Todo el enfoque puede parecer un poco complejo, pero una vez que haya creado las dos clases base para actividades y diálogos, es bastante fácil de usar y funciona perfectamente. Se puede utilizar para otras
Fragment
operaciones basadas que podrían verse afectadas por el mismo problema.fuente
Este error parece estar ocurriendo porque los eventos de entrada (como los eventos de pulsación de tecla o al hacer clic) se entregan después de la
onSaveInstanceState
llamada.La solución es anular
onSaveInstanceState
su actividad y cancelar cualquier evento pendiente.fuente