157 votes

Lors de l'affichage du dialogue, j'obtiens "Can not perform this action after onSaveInstanceState".

Certains utilisateurs signalent que s'ils utilisent l'action rapide dans la barre de notification, ils obtiennent une fermeture forcée.

Je montre une action rapide dans la notification qui appelle la "TestDialog" classe. Dans la classe TestDialog, après avoir appuyé sur le bouton "snooze", je vais afficher le 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");
}

L'erreur est *IllegalStateException: Can not perform this action after onSaveInstanceState*.

La ligne de code où l'exception IllegarStateException est déclenchée est la suivante :

snoozeDialog.show(fm, "snooze_dialog");

La classe étend "FragmentActivity" et la classe "SnoozeDialog" étend "DialogFragment".

Voici la trace complète de l'erreur :

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)

Je ne peux pas reproduire cette erreur, mais je reçois de nombreux rapports d'erreur.

Quelqu'un peut-il m'aider à réparer cette erreur ?

80voto

Rafael Points 2948

C'est courant numéro . Nous avons résolu ce problème en surchargeant show() et en gérant les exceptions dans la classe étendue DialogFragment.

public class CustomDialogFragment extends DialogFragment {

    @Override
    public void show(FragmentManager manager, String tag) {
        try {
            FragmentTransaction ft = manager.beginTransaction();
            ft.add(this, tag);
            ft.commit();
        } catch (IllegalStateException e) {
            Log.d("ABSDIALOGFRAG", "Exception", e);
        }
    }
}

Notez que l'application de cette méthode ne modifiera pas les champs internes de la classe DialogFragment.class :

boolean mDismissed;
boolean mShownByMe;

Cela peut conduire à des résultats inattendus dans certains cas. Il est préférable d'utiliser commitAllowingStateLoss() au lieu de commit().

43voto

PenguinDan Points 465

L'utilisation des nouveaux scopes du cycle de vie de Activity-KTX est aussi simple que l'exemple de code suivant :

lifecycleScope.launchWhenResumed {
   showErrorDialog(...)
}

Cette méthode peut être appelée directement après onStop() et affichera avec succès le dialogue une fois que onResume() aura été appelé au retour.

33voto

GZ95 Points 590

Cela signifie que vous commit() ( show() dans le cas d'un DialogFragment) le fragment suivant onSaveInstanceState() .

Android enregistrera l'état de votre fragment à onSaveInstanceState() . Donc, si vous commit() après onSaveInstanceState() l'état du fragment sera perdu.

En conséquence, si l'activité est tuée et recréée plus tard, le fragment ne sera pas ajouté à l'activité, ce qui est une mauvaise expérience pour l'utilisateur. C'est pourquoi Android ne permet pas la perte d'état à tout prix.

La solution simple consiste à vérifier si l'état a déjà été enregistré.

boolean mIsStateAlreadySaved = false;
boolean mPendingShowDialog = false;

@Override
public void onResumeFragments(){
    super.onResumeFragments();
    mIsStateAlreadySaved = false;
    if(mPendingShowDialog){
        mPendingShowDialog = false;
        showSnoozeDialog();
    }
}

@Override
public void onPause() {
    super.onPause();
    mIsStateAlreadySaved = true;
}

private void showSnoozeDialog() {
    if(mIsStateAlreadySaved){
        mPendingShowDialog = true;
    }else{
        FragmentManager fm = getSupportFragmentManager();
        SnoozeDialog snoozeDialog = new SnoozeDialog();
        snoozeDialog.show(fm, "snooze_dialog");
    }
}

Note : onResumeFragments() sera appelé lorsque les fragments seront repris.

23voto

huu duy Points 1218
private void showSnoozeDialog() {
    FragmentManager fm = getSupportFragmentManager();
    SnoozeDialog snoozeDialog = new SnoozeDialog();
    // snoozeDialog.show(fm, "snooze_dialog");
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.add(snoozeDialog, "snooze_dialog");
    ft.commitAllowingStateLoss();
}

réf : lien

17voto

Dennis Zinkovski Points 878

Après quelques jours, j'ai voulu partager la solution que j'ai trouvée. Pour afficher le DialogFragment, vous devez surcharger la fonction show() et appeler commitAllowingStateLoss() sur Transaction objet. Voici un exemple en Kotlin :

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

        }

    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X