Acciones en onActivityResult y "Error No se puede realizar esta acción después de onSaveInstanceState"

Al implementar una aplicación donde el usuario puede iniciar sesión, tengo la siguiente situación: si el usuario ha iniciado sesión, realice la acción; de lo contrario, inicie la actividad de inicio de sesión para obtener el resultado y, si el resultado es Activity.RESULT_OK, realice la acción.

Mi problema es que la acción a realizar es mostrar un DialogFragment, pero llamando

DialogFragment newFragment = MyDialogFragment.newInstance(mStackLevel);
newFragment.show(ft, "dialog")

en la devolución de llamada onActivityResult arroja una excepción:

Caused by: java.lang.IllegalStateException:  
Can not perform this action after onSaveInstanceState

Entonces, ¿cómo puedo resolver esto? Estoy pensando en levantar una bandera allí y mostrar el diálogo en onResume pero veo esta solución un poco sucia

Editar: se agregó más código (estoy siguiendo este ejemplo para mostrar el Fragmento de diálogo

Cuando la acción es solicitada por el usuario:

... 
if (!user.isLogged()){
 startActivityForResult(new Intent(cnt, Login.class), REQUEST_LOGIN_FOR_COMMENT);
}

En el mismo fragmento

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_LOGIN_FOR_COMMENT && resultCode == Activity.RESULT_OK) {
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        DialogFragment newFragment = MyDialogFragment.newInstance();
        newFragment.show(ft, "dialog")
    }
}

Y si el usuario inicia sesión en las llamadas de actividad de inicio de sesión;

setResult(Activity.RESULT_OK);
finish();

preguntado el 24 de agosto de 12 a las 08:08

Creo que deberías publicar el código completo. Parece que está intentando mostrar el diálogo después de la pausa -

Revise androiddesignpatterns.com/2013/08/… para entender por qué sucede esto -

8 Respuestas

Lo mejor que se me ocurrió es no usar .show() sino hacer esto.

CheckinSuccessDialog dialog = new CheckinSuccessDialog();
//dialog.show(getSupportFragmentManager(), null);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(dialog, null);
ft.commitAllowingStateLoss();

Respondido el 17 de Septiembre de 12 a las 19:09

Aunque me funciona, me siento inseguro porque omitimos 2 variables: mDismissed = false; mMostradoPorMe = verdadero; Las variables anteriores se están modificando en la función show original. - Cheok Yan Cheng

mDismissed y mShowByMe parecen ser variables específicamente para rastrear si el diálogo fue mostrado/oculto por llamadas externas. En otras palabras, compensan exactamente este tipo de cosas. - vince blas

Cómo puede "eliminar" el cuadro de diálogo - Javier

¿Ha intentado llamar a super.onActivityResult() en la primera línea de activityOnResult? - letroll

llamar super.onActivityResult() lo arregló para mí, intente esto antes de hacer la solución. - chico saki

Aquí está la solución que funciona bien para mí.

private void alert(final String message) {
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(new Runnable() {
        public void run() {
            AlertDialogFragment alertDialogFragment = AlertDialogFragment.newInstance(message);
            alertDialogFragment.show(getFragmentManager(), ALERT_DIALOG_FRAGMENT);
        }
    });        
}

contestado el 31 de mayo de 13 a las 15:05

Si usaba un DialogFragment, lo único que funcionó para mí fue descartar el Fragmento con dissmissAllowingStateLoss()

Respondido 11 Feb 14, 12:02

Simplemente compruebo si una actividad está siendo destruida.

if (!getActivity().isFinishing()) {
    DialogFragment fragment = MyFragment.newInstance();
    fragment.show(getActivity().getSupportFragmentManager(), MyFragment.TAG);
}

Vea también https://stackoverflow.com/a/41813953/2914140. En DialogFragment escribir:

override fun show(manager: FragmentManager?, tag: String?) {
    try {
        val ft = manager?.beginTransaction()
        ft?.add(this, tag)
        ft?.commitAllowingStateLoss()
    } catch (ignored: IllegalStateException) {
    }
}

contestado el 03 de mayo de 20 a las 19:05

Anular show(Fragment manager, String tag) función que permite perder y cambiar el estado mDismissed = false; mShownByMe = true; de la función original por reflexión:

public class DialogParent extends DialogFragment {

    @Override
    public void show(FragmentManager manager, String tag) {
        try {
            Field mDismissed = DialogFragment.class.getDeclaredField("mDismissed");
            Field mShownByMe = DialogFragment.class.getDeclaredField("mShownByMe");
            mDismissed.setAccessible(true);
            mShownByMe.setAccessible(true);
            mDismissed.setBoolean(this, false);
            mShownByMe.setBoolean(this, true);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag);
        ft.commitAllowingStateLoss();
    }
}

Respondido el 12 de diciembre de 16 a las 07:12

También podría rodear el método de demostración de los padres con un intento de captura, donde en la captura agrega el cuadro de diálogo y usa su llamada de transacción commitAllowingStateLoss(). De esta manera no necesitas ningún reflejo. - SimónSimCity

Esto funciona de verdad.

CheckinSuccessDialog dialog = new CheckinSuccessDialog();
//dialog.show(getSupportFragmentManager(), null);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(dialog, null);
ft.commitAllowingStateLoss();

Pero sigue siendo malo, porque recibió el error "La actividad ha sido destruida"

ava.lang.IllegalStateException: Activity has been destroyed fragmentTransaction.commitAllowingStateLoss();

Entonces mi solución es agregar cheque if (!isFinishing()&&!isDestroyed())

CheckinSuccessDialog fragment = CheckinSuccessDialog.newInstance();

     if (fragment instanceof DialogFragment) {
                DialogFragment dialog = (DialogFragment) fragment;
                if (!dialog.isAdded()) {
                    fragmentTransaction.add(dialog, 
                          CheckinSuccessDialog.class.getName());
                    if (!isFinishing()&&!isDestroyed()) {
                        fragmentTransaction.commitAllowingStateLoss();
                    }
                }

al descartar:

FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
        Fragment fragment = getSupportFragmentManager().findFragmentByTag(CheckinSuccessDialog.class.getName());
        if (fragment != null && fragment instanceof DialogFragment) {
            DialogFragment dialog = (DialogFragment) fragment;
            dialog.dismiss();
            if (!isFinishing()&&!isDestroyed()) {
                fragmentTransaction.commitAllowingStateLoss();
            }
        }

contestado el 13 de mayo de 17 a las 17:05

Esta excepción se lanza cada vez que un FragmentTrasaction se comete después FragmentManager ha guardado su estado. La manera fácil y limpia es comprobar si FragmentManager ya ha guardado el estado antes de mostrar un DialogFragment.

if(!getSupportFragmentManager.isStateSaved()) {
    MyDialogFragment dialogFragment = new MyDialogFragment()
    dialogFragment.show(getSupportFragmentManager, TAG);
}

respondido 29 nov., 17:05

Deberías llamar super.onActivityResult() antes de mostrar el diálogo

Respondido 24 Oct 21, 04:10

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.