Android 如果在后台按住导航抽屉项目时应用程序崩溃

Android application crashes if backgrounded while holding navigation drawer item

我有一个应用程序根据 Android 开发者网站实施使用导航抽屉设计模式。基本上列表中的每个项目都会打开一个片段(按照正常范例)。我发现,如果我在应用程序处于后台时按住其中一个导航抽屉项目(这可以通过按下主页键或在 phone 调用进入时完成),应用程序会崩溃。

值得注意的是,当我将手指从屏幕上移开时会发生崩溃,因此您可以将手指无限期地放在屏幕上,直到松开手指才会崩溃。

Stacktrace 如下,...所以我似乎可以马上回答我自己的问题 - 感谢您的(现在很明显)提示:-)

07-29 09:11:03.182    5044-5044/au.com.xxx.yyy E/AndroidRuntime﹕ FATALEXCEPTION: main
Process: au.com.xxx.yyy, PID: 5044
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
        at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1323)
        at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1341)
        at android.app.BackStackRecord.commitInternal(BackStackRecord.java:597)
        at android.app.BackStackRecord.commit(BackStackRecord.java:575)
        at au.com.xxx.yyy.userInterface.MainActivity.onNavigationDrawerItemSelected(MainActivity.java:264)
        at au.com.xxx.yyy.userInterface.NavigationDrawerFragment.selectItem(NavigationDrawerFragment.java:235)
        at au.com.xxx.yyy.userInterface.NavigationDrawerFragment.onItemClick(NavigationDrawerFragment.java:104)
        at android.widget.AdapterView.performItemClick(AdapterView.java:308)
        at android.widget.AbsListView.performItemClick(AbsListView.java:1478)
        at android.widget.AbsListView$PerformClick.run(AbsListView.java:3480)
        at android.widget.AbsListView.onTouchUp(AbsListView.java:4838)
        at android.widget.AbsListView.onTouchEvent(AbsListView.java:4601)
        at android.view.View.dispatchTouchEvent(View.java:8017)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2405)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2129)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2411)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2144)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2280)
        at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1615)
        at android.app.Activity.dispatchTouchEvent(Activity.java:2544)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2228)
        at android.view.View.dispatchPointerEvent(View.java:8212)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4499)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4367)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3925)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3979)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3948)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4059)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3956)
        at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4116)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3925)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3979)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3948)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3956)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3925)
        at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6306)
        at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6210)
        at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6181)
        at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6146)
        at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6386)
        at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:138)
        at android.os.Looper.loop(Looper.java:123)
        at android.app.ActivityThread.main(ActivityThread.java:5356)

对于任何遵循答案的人来说,答案都非常简单(并且由堆栈跟踪暗示 - 感谢 Ashwin)。

在显示片段和使后退按钮起作用的标准模式中如下所示:

public void onNavigationDrawerItemSelected(int position, boolean fromSavedInstanceState) {
    ....
    ....
    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    // Replace whatever is in the fragment_container view with this fragment,
    // and add the transaction to the back stack
    transaction.replace(R.id.container, fragment);
    // add transaction to back stack so it can be reversed
    transaction.addToBackStack(null);
    // Commit the transaction
    transaction.commit();
}

如果您已经执行了 onSaveInstanceState(...) 调用,那么 transaction.commit() 行会抛出上面显示的异常。

因此我创建了一个标志来说明我当前是否正在处理我在 onCreate 和 onResume 中清除的 onSaveInstanceState 调用。然后我使用这个标志绕过 onNavigationDrawerItemSelected(...)

中的所有 BackStack 内容

瞧!一旦你把头放在正确的位置就很明显!!