DialogFragment - 无法在 onSaveInstanceState 后执行此操作

12

我正在开发一个启动器应用程序,当用户进行身份验证时,它会显示一个DialogFragment。大多数情况下,这个应用程序运行良好,但有时我会遇到这个错误日志:

02-07 18:55:56.619: E/AndroidRuntime(1300): java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1280)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1291)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.BackStackRecord.commitInternal(BackStackRecord.java:548)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.BackStackRecord.commit(BackStackRecord.java:532)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.DialogFragment.dismissInternal(DialogFragment.java:292)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.DialogFragment.dismiss(DialogFragment.java:258)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at com.blablabla.android.app.fragments.login.LoginResultFragment$CloseDialogRunnable.run(LoginResultFragment.java:59)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.os.Handler.handleCallback(Handler.java:615)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.os.Handler.dispatchMessage(Handler.java:92)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.os.Looper.loop(Looper.java:137)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at android.app.ActivityThread.main(ActivityThread.java:4745)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at java.lang.reflect.Method.invokeNative(Native Method)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at java.lang.reflect.Method.invoke(Method.java:511)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
02-07 18:55:56.619: E/AndroidRuntime(1300):     at dalvik.system.NativeStart.main(Native Method)

我在其他线程中搜索过,例如这个,并且按照他们的建议去尝试了,但对我来说仍然没有作用。

我的DialogFragment看起来是这样的:

public class LoginResultFragment extends DialogFragment implements
        OnClickListener {

    private CloseDialogRunnable runnable = null;

    public class CloseDialogRunnable implements Runnable {
        /**
         * https://dev59.com/NG025IYBdhLWcg3wtoVA
         * stopping-runnable
         */
        private boolean killCloseActivityRunnable = false;

        public void killRunnable() {
            killCloseActivityRunnable = true;
        }

        @Override
        public void run() {
            if (killCloseActivityRunnable) {
                return;
            }
            if (getDialog()!=null && getDialog().isShowing()) {             
                    dismiss();              
            }
        }
    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        if (runnable != null){      
            runnable.killRunnable();
            handler.removeCallbacks(runnable);
        }
        super.onDismiss(dialog);
    }

    /** Milliseconds until we dismiss the timeout */
    private static final long DISMISSING_TIMEOUT = 2000;

    /** Dismissing window handler */
    private final Handler handler = new Handler();

    private LoginResultFragment() {
    }

    public static LoginResultFragment getInstance(
            Map<String, Object> currentValues) {
        LoginResultFragment result = new LoginResultFragment();

        set extra fields...

        return result;
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setStyle(DialogFragment.STYLE_NO_FRAME,
                android.R.style.Theme_Holo_Dialog);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        setRetainInstance(true);
        rootView = inflater.inflate(R.layout.fragment_login_result, container);

        getDialog().getWindow().setBackgroundDrawable(
                new ColorDrawable(android.graphics.Color.TRANSPARENT));

        do UI stuff...

        dismissAfterTimeout();
        return rootView;
    }

    private void dismissAfterTimeout() {
        runnable = new CloseDialogRunnable();
        handler.postDelayed(runnable, DISMISSING_TIMEOUT);

    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
    }

}

我用以下方式来调用它:

final android.app.FragmentTransaction trans = activity
                .getFragmentManager().beginTransaction();
        trans.add(fragment, fragment.getClass().getCanonicalName());
        trans.commitAllowingStateLoss();

你能否在FragmentTransaction的执行位置上添加更多细节?我看到你正在将Fragment添加到事务管理器中,但是你是否将其添加到了布局中?接下来会发生什么,可能会导致Fragment的onSaveInstanceState()被调用(暂停、完成活动等)? - jacobhyphenated
嗨,jacobhyphenated,感谢您的评论。我没有将该片段添加到布局中,因为我像对话框一样显示它(它是DialogFragment)。当我从其他进程接收到一些登录信息时,我会显示它。 - Guillermo Merino
可能是重复的问题:如何在onActivityResult中显示DialogFragment - rds
我已经制作了一个替代DialogFragment的解决方案,可以避免这个异常:https://github.com/AndroidDeveloperLB/DialogShard - android developer
2个回答

12

您可以使用以下内容:

if (!StartActivity.this.isFinishing())
{
    //showdialog fragment
}

在显示对话框之前检查活动是否未结束。


谢谢您的回复,我的问题出在CloseDialogRunnable上,我会更新它并提供可行的答案。 - Guillermo Merino

1

最终,解决问题的方法是修改CloseDialogRunnable,以下是有效代码:

public class CloseDialogRunnable implements Runnable {
    /**
     * https://dev59.com/NG025IYBdhLWcg3wtoVA
     * stopping-runnable
     */
    private boolean killCloseActivityRunnable = false;

    public void killRunnable() {
        killCloseActivityRunnable = true;
    }

    @Override
    public void run() {
        if (killCloseActivityRunnable) {
            return;
        }
        if (getDialog() != null && getDialog().isShowing() && isResumed()) {
            try {
                dismiss();
            } catch (IllegalArgumentException e) {
                Log.e(TAG, "Error dismissing");
            }
        }
    }
}

3
是IllegalArgumentException还是IllegalStateException?你所做的只是吞掉了异常。我不觉得这是一个真正的解决方案。解决方案应该是预防异常的出现。 - rpattabi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接