在显示对话框时,我得到“ onSaveInstanceState之后无法执行此操作”


121

一些用户正在报告,如果他们使用通知栏中的快速操作,则他们将被强制关闭。

我在通知中显示了一个快速操作,该通知调用了“ TestDialog”类。在按下“ snooze”按钮后的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)

我无法重现此错误,但是我收到了很多错误报告。

谁能帮我解决这个错误?


2
您找到解决方案了吗?我和你有同样的问题。我在这里问过:stackoverflow.com/questions/15730878/… 请检查我的问题,并查看可能不适用于我的情况的解决方案。也许它将为您工作。
rootpanthera

尚无解决方法:-(并且您的建议已添加到我的课程中
。– chrisonline

从此处检查已接受的答案。这解决了我的问题: stackoverflow.com/questions/14177781/…–
bogdan

4
触发此对话框时,您的活动是否可见?听起来这可能是由于您的应用试图显示附加到已暂停/停止的活动的对话框所致。
2014年

stackoverflow.com/questions/7575921/…您已经尝试过此确定性。
Orion

Answers:


66

这是普遍的问题。我们通过重写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;

在某些情况下,这可能会导致意外结果。最好使用commitAllowingStateLoss()而不是commit()


3
但是为什么会发生此问题?可以忽略该错误吗?当您这样做时会发生什么?毕竟,单击时表示活动进行得很顺利……无论如何,我在这里报告了此问题,因为我认为这是一个错误:code.google.com/p/android/issues/detail?id= 207269
android开发人员

1
那么,您可以在其中加注星标和/或发表评论吗?
Android开发人员

2
最好在try-catch子句中调用super.show(manager,tag)。DialogFragment拥有的标志可以这种方式保持安全
Shayan_Aryan

19
此时,您可以调用commitAllowingStateLoss()而不是commit()。不会引发异常。
ARLabs

1
@ARLabs我想在这种情况下,也对应答者会更好,因为如果您仅捕获此处显示的异常,则肯定不会显示该对话框。如果可以的话,最好显示对话框,如果必须恢复状态,对话框可能会消失。另外,请在后台将应用程序的内存使用率保持在较低水平,以免被破坏。
androidguy

27

这意味着您commit()show()在DialogFragment的情况下)在之后进行分段onSaveInstanceState()

Android会将您的片段状态保存在onSaveInstanceState()。因此,如果您commit()接连onSaveInstanceState()碎片,碎片状态将丢失。

结果,如果Activity被杀死并在以后重新创建,那么该片段将不会添加到不良用户体验的Activity中。这就是为什么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()。


1
如果我想在另一个片段中显示DialogFragment怎么办?
Android开发人员

我们的解决方案是创建活动和片段基类,并将onResumeFragments委托给片段(我们在片段基类中创建onResumeFragments)。这不是很好的解决方案,但确实可以。如果您有更好的解决方案,请让我知道:)
Pongpat

好吧,我认为在“ onStart”中显示对话框应该可以正常工作,因为肯定会显示该片段,但是我仍然看到一些崩溃报告。指示我尝试将其放在“ onResume”上。关于替代方案,我看到了这一点:twigstechtips.blogspot.co.il/2014/01/…,但这很奇怪。
Android开发人员

我认为twigstechtips.blogspot.co.il/2014/01/…之所以起作用的原因是,它启动了新线程,因此在代码runOnUiThread运行之前调用了所有生命周期代码,即onStart,onResume等。这意味着在调用runOnUiThread之前状态已经恢复。
Pongpat

2
我使用单个调用来发布(可运行)。关于getFragmentManager,取决于。如果要与另一个活动共享该对话框,则应使用getFragmentManager,但是,如果该对话框仅与片段一起存在,则getChildFragmentManager似乎是一个更好的选择。
Pongpat

16
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();
}

参考:链接


11

几天后,我想分享我的解决方案如何,我已经修复它,以示DialogFragment你应该重写show()它的方法和调用commitAllowingStateLoss()Transaction对象。这是Kotlin中的示例:

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

        }

    }

1
为了使开发人员不必从DialogFragment您那里继承,可以将其更改为具有以下签名的Kotlin扩展功能:fun DialogFragment.showAllowingStateLoss(fragmentManager: FragmentManager, tag: String)。另外,try-catch并不是必需的,因为您要调用commitAllowingStateLoss()方法而不是commit()方法。
阿迪尔·侯赛因

10

如果对话框不是很重要(可以关闭应用程序/不再显示该视图就可以不显示该对话框),请使用:

boolean running = false;

@Override
public void onStart() {
    running = true;
    super.onStart();
}

@Override
public void onStop() {
    running = false;
    super.onStop();
}

并仅在运行时打开对话框(片段):

if (running) {
    yourDialog.show(...);
}

编辑,可能更好的解决方案:

在生命周期中调用onSaveInstanceState的位置是不可预测的,我认为更好的解决方案是像这样检查isSavedInstanceStateDone():

/**
 * True if SavedInstanceState was done, and activity was not restarted or resumed yet.
 */
private boolean savedInstanceStateDone;

@Override
protected void onResume() {
    super.onResume();

    savedInstanceStateDone = false;
}

@Override
protected void onStart() {
    super.onStart();

    savedInstanceStateDone = false;
}

protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    savedInstanceStateDone = true;
}


/**
 * Returns true if SavedInstanceState was done, and activity was not restarted or resumed yet.
 */
public boolean isSavedInstanceStateDone() {
    return savedInstanceStateDone;
}

这似乎不起作用,因为我在“ onStart”方法调用中遇到了此异常(试图在那里显示DialogFragment)。
Android开发人员

你救了我的日子。谢谢弗兰克。
库内特'16

7

我已经遇到这个问题很多年了。
互联网上散布着成百上千(数百?数千?)关于此的讨论,并且其中的困惑和虚假信息似乎很多。
为了使情况变得更糟,本着xkcd“ 14标准”漫画的精神,我将答案投了出去。
xkcd 14标准

cancelPendingInputEvents()commitAllowingStateLoss()catch (IllegalStateException e),和类似的解决方案都显得残酷。

希望以下内容可以轻松地显示如何重现和解决该问题:

private static final Handler sHandler = new Handler();
private boolean mIsAfterOnSaveInstanceState = true;

@Override
protected void onSaveInstanceState(Bundle outState)
{
    super.onSaveInstanceState(outState);
    mIsAfterOnSaveInstanceState = true; // <- To repro, comment out this line
}

@Override
protected void onPostResume()
{
    super.onPostResume();
    mIsAfterOnSaveInstanceState = false;
}

@Override
protected void onResume()
{
    super.onResume();
    sHandler.removeCallbacks(test);
}

@Override
protected void onPause()
{
    super.onPause();
    sHandler.postDelayed(test, 5000);
}

Runnable test = new Runnable()
{
    @Override
    public void run()
    {
        if (mIsAfterOnSaveInstanceState)
        {
            // TODO: Consider saving state so that during or after onPostResume a dialog can be shown with the latest text
            return;
        }

        FragmentManager fm = getSupportFragmentManager();
        DialogFragment dialogFragment = (DialogFragment) fm.findFragmentByTag("foo");
        if (dialogFragment != null)
        {
            dialogFragment.dismiss();
        }

        dialogFragment = GenericPromptSingleButtonDialogFragment.newInstance("title", "message", "button");
        dialogFragment.show(fm, "foo");

        sHandler.postDelayed(test, 5000);
    }
};

2
我爱那些没有任何解释的投反对票的人。取而代之的只是反对投票,也许会更好,如果他们解释我的解决方案是如何有缺陷?我可以投反对票吗?
swooby

1
是的,这是SO的问题,我每次都在建议中写这个问题,但他们不想解决。
CoolMind的

2
我认为不赞成投票可能是嵌入式XKCD的结果,答案实际上并不是社交评论的地方(无论多么有趣和/或真实)。
RestingRobot

6

请尝试使用FragmentTransaction而不是FragmentManager。我认为以下代码将解决您的问题。如果没有,请告诉我。

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

编辑:

片段交易

请检查此链接。我认为它将解决您的疑问。


4
关于为什么使用FragmentTransaction可以解决此问题的任何解释都很好。
Hemanshu 2014年

3
Dialog#show(FragmentManager,tag)做同样的事情。这不是解决方案。
威廉

3
这个答案不是解决方案。DialogFragment#show(ft)和show(fm)完全一样。
danijoo 2015年

@danijoo是正确的,两者都可以完成相同的工作。但是在少数电话中,如果您使用fragmentmanager而不是fragmenttransaction,就会有类似的问题。因此,就我而言,这解决了我的问题。
RIJO RV 2015年

5

使用Activity-KTX的新生命周期范围,就像以下代码示例一样简单:

lifecycleScope.launchWhenResumed {
   showErrorDialog(...)
}

可以在onStop()之后直接调用此方法,并且一旦返回就调用onResume(),它将成功显示对话框。


3

许多视图将高级事件(例如单击处理程序)发布到事件队列中以推迟运行。因此,问题在于已经为Activity调用了“ onSaveInstanceState”,但事件队列包含了延迟的“单击事件”。因此,当此事件分派给您的处理程序时

at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)

并且您的代码会show引发IllegalStateException。

最简单的解决方案是清理事件队列, onSaveInstanceState

protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        // ..... do some work
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            findViewById(android.R.id.content).cancelPendingInputEvents();
        }
}

您实际上已经确认这可以解决问题吗?
mhsmith '19

Google已将此版本添加到了androidx库的下一个版本中,目前处于beta(activityfragment)状态。
mhsmith

1
@mhsmith我确实记得该解决方案通过IllegalStateException解决了我代码中的问题
sim

2

使您的对话框片段对象成为全局对象,并在onPause()方法中调用dismissAllowingStateLoss()

@Override
protected void onPause() {
    super.onPause();

    if (dialogFragment != null) {
        dialogFragment.dismissAllowingStateLoss();
    }
}

不要忘记在片段中分配值,并在单击按钮或任何地方调用show()。


1

尽管在任何地方都没有正式提到它,但是我几次遇到了这个问题。以我的经验,兼容性库在较旧平台上支持片段存在问题,这会导致此问题。您可以通过使用常规片段管理器API对此进行测试。如果没有任何效果,则可以使用普通对话框代替对话框片段。


1
  1. 将此类添加到您的项目中:(必须位于android.support.v4.app包中)
包android.support.v4.app;


/ **
 *由Gil于8/16/2017创建。
 * /

公共类StatelessDialogFragment扩展DialogFragment {
    / **
     *显示对话框,使用现有事务添加片段,然后提交
     *交易,同时允许状态损失。
* *我建议您大多数时候都使用{@link #show(FragmentTransaction,String)},但 *这是您完全不关心的对话框。(调试/跟踪/广告等) * * @参数交易 *在其中添加片段的现有事务。 * @param标签 *此片段的标签,按照 * {@link FragmentTransaction#add(Fragment,String)FragmentTransaction.add}。 * @return返回已提交事务的标识符,按照 * {@link FragmentTransaction#commit()FragmentTransaction.commit()}。 * @see StatelessDialogFragment#showAllowingStateLoss(FragmentManager,String) * / public int showAllowingStateLoss(FragmentTransaction transaction,String tag) { mDismissed =假; mShownByMe = true; transaction.add(this,tag); mViewDestroyed = false; mBackStackId = transaction.commitAllowingStateLoss(); 返回mBackStackId; } / ** *显示对话框,将片段添加到给定的FragmentManager中。这很方便 *用于显式创建事务,并使用给定标签将片段添加到其中,以及 *提交它而不关心状态。这并没有交易添加到 *返回堆栈。当片段被消除时,将执行新的事务以将其删除 *来自活动。
* *我建议您大多数时候都使用{@link #show(FragmentManager,String)},但这是 *用于您根本不关心的对话框。(调试/跟踪/广告等) * * * @参数经理 *该片段将被添加到FragmentManager。 * @param标签 *此片段的标签,按照 * {@link FragmentTransaction#add(Fragment,String)FragmentTransaction.add}。 * @see StatelessDialogFragment#showAllowingStateLoss(FragmentTransaction,String) * / 公共无效的showAllowingStateLoss(FragmentManager管理器,字符串标记) { mDismissed =假; mShownByMe = true; FragmentTransaction ft = manager.beginTransaction(); ft.add(this,tag); ft.commitAllowingStateLoss(); } }
  1. 扩展StatelessDialogFragment而不是DialogFragment
  2. 使用方法showAllowingStateLoss代替show

  3. 请享用 ;)


这些所有布尔字段是做什么用的?为什么不将它们声明为类成员?
不确定

1
布尔字段是DialogFragment的受保护成员,它们的名称显然表明了它们的用途,我们需要对其进行更新,以免干扰DialogFragment的逻辑。请注意,在原始DialogFragment类中,该函数存在但没有公共访问权限
Gil SH

这些成员没有受到保护,它们是内部的。当我将其StatelessDialogFragment放入一个软件包中时,我遇到了编译错误。感谢老兄,我将在生产中对其进行测试。
不确定

1

使用此代码

FragmentTransaction ft = fm.beginTransaction();
        ft.add(yourFragment, "fragment_tag");
        ft.commitAllowingStateLoss();

代替

yourFragment.show(fm, "fragment_tag");

1

通过使用反射,我已经找到了解决此问题的理想解决方案。上述所有解决方案的问题是,字段mDismissedmShownByMe不会更改其状态。

只需在您自己的自定义底部工作表对话框片段中覆盖方法“ show”,如下面的示例(Kotlin)

override fun show(manager: FragmentManager, tag: String?) {
        val mDismissedField = DialogFragment::class.java.getDeclaredField("mDismissed")
        mDismissedField.isAccessible = true
        mDismissedField.setBoolean(this, false)

        val mShownByMeField = DialogFragment::class.java.getDeclaredField("mShownByMe")
        mShownByMeField.isAccessible = true
        mShownByMeField.setBoolean(this, true)

        manager.beginTransaction()
                .add(this, tag)
                .commitAllowingStateLoss()
    }

4
“通过反射,我已经找到了解决该问题的理想解决方案。” 怎么样?
Mark Buikema

优雅,时尚,别致,聪明,漂亮,优雅
РомаБогдан

1
这是唯一对我有用的解决方案。我认为这很优雅
MBH

0

以下实现可用于解决在Activity生命周期中安全地执行状态更改的问题,尤其是用于显示对话框的问题:如果实例状态已经保存(例如由于配置更改),它将推迟状态直到恢复到已恢复状态为止被执行。

public abstract class XAppCompatActivity extends AppCompatActivity {

    private String TAG = this.getClass().getSimpleName();

    /** The retained fragment for this activity */
    private ActivityRetainFragment retainFragment;

    /** If true the instance state has been saved and we are going to die... */
    private boolean instanceStateSaved;

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        // get hold of retain Fragment we'll be using
        retainFragment = ActivityRetainFragment.get(this, "Fragment-" + this.getClass().getName());
    }

    @Override
    protected void onPostResume() {
        super.onPostResume();

        // reset instance saved state
        instanceStateSaved = false;

        // execute all the posted tasks
        for (ActivityTask task : retainFragment.tasks) task.exec(this);
        retainFragment.tasks.clear();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        instanceStateSaved = true;
    }

    /**
     * Checks if the activity state has been already saved.
     * After that event we are no longer allowed to commit fragment transactions.
     * @return true if the instance state has been saved
     */
    public boolean isInstanceStateSaved() {
        return instanceStateSaved;
    }

    /**
     * Posts a task to be executed when the activity state has not yet been saved
     * @param task The task to be executed
     * @return true if the task executed immediately, false if it has been queued
     */
    public final boolean post(ActivityTask task)
    {
        // execute it immediately if we have not been saved
        if (!isInstanceStateSaved()) {
            task.exec(this);
            return true;
        }

        // save it for better times
        retainFragment.tasks.add(task);
        return false;
    }

    /** Fragment used to retain activity data among re-instantiations */
    public static class ActivityRetainFragment extends Fragment {

        /**
         * Returns the single instance of this fragment, creating it if necessary
         * @param activity The Activity performing the request
         * @param name The name to be given to the Fragment
         * @return The Fragment
         */
        public static ActivityRetainFragment get(XAppCompatActivity activity, String name) {

            // find the retained fragment on activity restarts
            FragmentManager fm = activity.getSupportFragmentManager();
            ActivityRetainFragment fragment = (ActivityRetainFragment) fm.findFragmentByTag(name);

            // create the fragment and data the first time
            if (fragment == null) {
                // add the fragment
                fragment = new ActivityRetainFragment();
                fm.beginTransaction().add(fragment, name).commit();
            }

            return fragment;
        }

        /** The queued tasks */
        private LinkedList<ActivityTask> tasks = new LinkedList<>();

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

            // retain this fragment
            setRetainInstance(true);
        }

    }

    /** A task which needs to be performed by the activity when it is "fully operational" */
    public interface ActivityTask {

        /**
         * Executed this task on the specified activity
         * @param activity The activity
         */
        void exec(XAppCompatActivity activity);
    }
}

然后使用这样的类:

/** AppCompatDialogFragment implementing additional compatibility checks */
public abstract class XAppCompatDialogFragment extends AppCompatDialogFragment {

    /**
     * Shows this dialog as soon as possible
     * @param activity The activity to which this dialog belongs to
     * @param tag The dialog fragment tag
     * @return true if the dialog has been shown immediately, false if the activity state has been saved
     *         and it is not possible to show it immediately
     */
    public boolean showRequest(XAppCompatActivity activity, final String tag) {
        return showRequest(activity, tag, null);
    }

    /**
     * Shows this dialog as soon as possible
     * @param activity The activity to which this dialog belongs to
     * @param tag The dialog fragment tag
     * @param args The dialog arguments
     * @return true if the dialog has been shown immediately, false if the activity state has been saved
     *         and it is not possible to show it immediately
     */
    public boolean showRequest(XAppCompatActivity activity, final String tag, final Bundle args)
    {
        return activity.post(new XAppCompatActivity.ActivityTask() {
            @Override
            public void exec(XAppCompatActivity activity) {
                if (args!= null) setArguments(args);
                show(activity.getSupportFragmentManager(), tag);
            }
        });
    }

    /**
     * Dismiss this dialog as soon as possible
     * @return true if the dialog has been dismissed immediately, false if the activity state has been saved
     *         and it is not possible to dismissed it immediately
     */
    public boolean dismissRequest()
    {
        return dismissRequest(null);
    }

    /**
     * Dismiss this dialog as soon as possible
     * @param runnable Actions to be performed before dialog dismissal
     * @return true if the dialog has been dismissed immediately, false if the activity state has been saved
     *         and it is not possible to dismissed it immediately
     */
    public boolean dismissRequest(final Runnable runnable)
    {
        // workaround as in rare cases the activity could be null
        XAppCompatActivity activity = (XAppCompatActivity)getActivity();
        if (activity == null) return false;

        // post the dialog dismissal
        return activity.post(new XAppCompatActivity.ActivityTask() {
            @Override
            public void exec(XAppCompatActivity activity) {
                if (runnable != null) runnable.run();
                dismiss();
            }
        });
    }
}

您可以安全地显示对话框,而不必担心应用程序状态:

public class TestDialog extends XAppCompatDialogFragment {

    private final static String TEST_DIALOG = "TEST_DIALOG";

    public static void show(XAppCompatActivity activity) {
        new TestDialog().showRequest(activity, TEST_DIALOG);
    }

    public TestDialog() {}

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState)
    {
        return new AlertDialog.Builder(getActivity(), R.style.DialogFragmentTheme /* or null as you prefer */)
                .setTitle(R.string.title)
                // set all the other parameters you need, e.g. Message, Icon, etc.
                ).create();
    }
}

然后TestDialog.show(this)从您的内部呼叫XAppCompatActivity

如果要使用参数创建更通用的对话框类,可以将它们Bundleshow()方法中的参数一起保存在中,并使用getArguments()in进行检索onCreateDialog()

整个方法似乎有点复杂,但是一旦为活动和对话框创建了两个基类,它就很容易使用并且可以正常工作。它可以用于Fragment可能受同一问题影响的其他基于基础的操作。


0

发生此错误的原因是,在onSaveInstanceState调用之后将传递输入事件(例如按键或onclick事件)。

解决方案是onSaveInstanceState在“活动”中覆盖并取消所有未决事件。

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        final View rootView = findViewById(android.R.id.content);
        if (rootView != null) {
            rootView.cancelPendingInputEvents();
        }
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.