134

一部のユーザーは、通知バーでクイック アクションを使用すると、強制終了されると報告しています。

「TestDialog」クラスを呼び出す通知でクイック アクションを示します。「スヌーズ」ボタンを押した後の TestDialog クラスでは、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");
}

エラーは*IllegalStateException: Can not perform this action after onSaveInstanceState*.

IllegarStateException が発生するコード行は次のとおりです。

snoozeDialog.show(fm, "snooze_dialog");

クラスは「FragmentActivity」を拡張しており、「SnoozeDialog」クラスは「DialogFragment」を拡張しています。

エラーの完全なスタック トレースは次のとおりです。

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)

このエラーを再現することはできませんが、多くのエラー レポートを受け取っています。

どうすればこのエラーを修正できますか?

4

17 に答える 17

73

これはよくある問題です。show() をオーバーライドし、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);
        }
    }
}

このメソッドを適用しても、DialogFragment.class の内部フィールドは変更されないことに注意してください。

boolean mDismissed;
boolean mShownByMe;

これにより、場合によっては予期しない結果が生じる可能性があります。commit() の代わりに commitAllowingStateLoss() を使用することをお勧めします

于 2016-02-16T11:22:00.417 に答える
29

つまり、commit()( show()DialogFragment の場合) の後にフラグメント化しonSaveInstanceState()ます。

Android は、フラグメントの状態を に保存しますonSaveInstanceState()。そのため、フラグメント状態をcommit()次々にonSaveInstanceState()フラグメント化すると、失われます。

その結果、アクティビティが強制終了されて後で再作成された場合、フラグメントがアクティビティに追加されず、ユーザー エクスペリエンスが低下します。これが、Android が状態の損失を絶対に許可しない理由です。

簡単な解決策は、状態が既に保存されているかどうかを確認することです。

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");
    }
}

注: onResumeFragments() は、フラグメントが再開されたときに呼び出されます。

于 2014-09-07T01:20:34.330 に答える
21
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();
}

参照:リンク

于 2016-10-20T18:25:30.620 に答える
6

FragmentManager の代わりに FragmentTransaction を使用してみてください。以下のコードで問題が解決すると思います。そうでない場合は、お知らせください。

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
SnoozeDialog snoozeDialog = new SnoozeDialog();
snoozeDialog.show(ft, "snooze_dialog");

編集:

フラグメント トランザクション

このリンクを確認してください。疑問が解決すると思います。

于 2013-12-26T11:42:26.170 に答える
2

show() 関数をオーバーライドする場合は、これを行わないでください。

override fun show(manager: FragmentManager, tag: String?) {
    // mDismissed = false; is removed -> lead to wrong state
    // mShownByMe = true; is removed -> lead to wrong state
    val ft = manager.beginTransaction()
    ft.add(this, tag)
    ft.commitAllowingStateLoss()
}

ダイアログの間違った状態につながる可能性があります

ただ行う:

override fun show(manager: FragmentManager, tag: String?) {
    try {
        super.show(manager, tag)
    } catch (e: Exception) {
        val ft = manager.beginTransaction()
        ft.add(this, tag)
        ft.commitAllowingStateLoss()
    }
}
于 2020-10-22T08:57:21.210 に答える