Llamar el show de DialogFragment () desde dentro onRequestPermissionsResult () provoca IllegalStateException en Marshmallow

Pasos:

  1. Solicitar un permiso de Fragment o Activity
  2. Mostrar un DialogFragment desde dentro onRequestPermissionsResult()
  3. java.lang.IllegalStateException se lanza: No se puede realizar esta acción después de onSaveInstanceState

Esto no sucede cuando muestro el diálogo después de algún retraso (usando postDelayed). De acuerdo con http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html ) en los dispositivos post-Honeycomb PODEMOS commit() entre onPause() y onStop() sin ninguna onStop() O EXCEPCIÓN. Aquí hay un enlace a la fuente del proyecto de ejemplo, el archivo de registro y el problema grabado. Https://drive.google.com/folderview?id=0BwvvuYbQTUl6STVSZF9TX2VUeHM&usp=sharing

También he abierto un problema https://code.google.com/p/android/issues/detail?id=190966 pero se ha marcado como WorkingAsIntended y sugieren que sólo capturar excepción. Pero esto no soluciona el problema. Conozco otras maneras de solucionarlo, pero ¿no es este error Android?

ACTUALIZACIÓN El estado del error se vuelve a asignar. Espero que se arreglen pronto. Mi solución temporal es

 new Handler().postDelayed(new Runnable() { @Override public void run() { // do your fragment transaction here } }, 200); 

El error se acepta y se solucionará, sin embargo, estoy en desacuerdo con las soluciones postDelayed y temporizador. La mejor manera de hacer esto sería introducir un indicador de estado en la Actividad, en el que se establece en la devolución de llamada, y utilizar en onResume o similar. Por ejemplo:

 private boolean someFlag; public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { // some code checking status someFlag = true; } 

Y luego en onResume:

 protected void onResume() { if(someFlag == true) { doSomething(); someFlag = false; } } 

Probar algo como esto:

 // ... private Runnable mRunnable; @Override public void onResume() { super.onResume(); if (mRunnable != null) { mRunnable.run(); mRunnable = null; } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (/* PERMISSION_DENIED */) { mRunnable = /* new Runnable which show dialogFragment*/; } } 

Se trata de un error en Android https://code.google.com/p/android/issues/detail?id=190966&q=label%3AReportedBy-Developer&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

Por lo tanto, por ahora, las soluciones son necesarias. Puede utilizar la solución de @ldulcic. O puede usar el método postDelay de Handler. Se prefiere la segunda opción.

Puesto que usted está utilizando un DialogFragment , usted debe guardar un indicador o un estado y que demuestre su diálogo en onPostResume . Debe hacer esto en onPostResume en lugar de onResume u otros métodos de ciclo de vida.

Como se indica claramente en la documentación , si se cometen transacciones en métodos de ciclo de vida de actividad distintos de onPostResume o onResumeFragments (para FragmentActivity), en algunos casos el método se puede llamar antes de que el estado de la actividad se haya restaurado completamente.

Por lo tanto, si muestra su diálogo onPostResume usted estará bien.

También creo que esto es un error de Android. No puedo creer que hayan marcado el problema WorkingAsIntended . La única solución para ahora es retrasar la ejecución del código en onRequestPermissionsResult() hasta que la gente de android corrija esto correctamente.

Esta es mi forma de resolver este problema si alguien se pregunta cómo retrasar la ejecución:

   @Override public void onRequestPermissionsResult (int requestCode, String [] permisos, int [] grantResults) {

     If (requestCode == PERMISSION_CODE) {
       If (/ * PERMISIÓN PERMITIDA / DENEGADA * /) {
           Nuevo Timer (). Schedule (new TimerTask () {
               @Override public void run () {
                   // EJECUTAR ACCIONES (LIKE FRAGMENT TRANSACTION ETC.)
               }
           }, 0);
       }
   }

Esto esencialmente retrasa la ejecución hasta que onRequestPermissionsResult() termine para que no obtengamos java.lang.IllegalStateException . Esto funciona en mi aplicación.

He superado esto en lo que creo que es una forma mucho más determinista. En lugar de usar temporizadores, básicamente coloqué el resultado hasta Activity.onResumeFragments () (o podrías hacerlo en Activity.onResume () si no usas fragmentos). Hice onResumeFragments () porque también encaminar el resultado fuera al fragmento específico que pidió el permiso así que necesito estar seguro que los fragmentos están listos.

Aquí está onRequestPermissionsResult ():

 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { // This is super ugly, but google has a bug that they are calling this method BEFORE // onResume... which screws up fragment lifecycle big time. So work around it. But also // be robust enough to still work if/when they fix the bug. if (mFragmentsResumed) { routePermissionsResult(requestCode, permissions, grantResults); } else { mQueuedPermissionGrantResults = grantResults; mQueuedPermissionRequestCode = requestCode; mQueuedPermissions = permissions; } } 

Entonces aquí está onResumeFragments ():

 @Override protected void onResumeFragments() { super.onResumeFragments(); mFragmentsResumed = true; if (mQueuedPermissionGrantResults != null) { routePermissionsResult(mQueuedPermissionRequestCode, mQueuedPermissions, mQueuedPermissionGrantResults); } 

Y para completar, aquí está onPause (), que borra el mFragmentsResumed flag:

 @Override protected void onPause() { super.onPause(); mFragmentsResumed = false; } 

Utilicé el indicador mFragmentsResumed porque no quiero que este código deje de funcionar si y cuando google corrige el error (cambiar el orden de las invocaciones del ciclo de vida haría que el código no funcionara si simplemente estaba estableciendo las variables en cola en onRequestPermissionsResult pero onResumeFragments was Llamado antes de esto).

  • Explorando checkCallingOrSelfPermission () para el ataque de escalado de privilegios
  • ActivityCompat.requestPermissions no muestra el mensaje
  • ¿Cuál es la mejor manera de comprobar los permisos en tiempo de ejecución mediante la arquitectura MVP?
  • Respondida Incoming Call in Android 6.0
  • Bloqueo antes de que se inicie la aplicación: SecurityException: denegación de permisos: INTERACT_ACROSS_USERS_FULL
  • Solicitar permisos de ubicación de un servicio Android M
  • ¿Puedo solicitar un permiso en ciertas versiones de Android?
  • No se puede resolver el símbolo Manifest.permission.READ_PHONE_STATE
  • "No se puede cambiar la configuración privada de seguridad" - ¿cómo cambiar la vibración del tono de llamada en Android 6?
  • ¿Por qué play-services-location necesita los permisos android.permission.WRITE_EXTERNAL_STORAGE y android.permission.READ_EXTERNAL_STORAGE?
  • Android Marshmallow - cómo saber "Nunca preguntar de nuevo" se comprueba antes
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.