我在市场上从我的应用程序获得用户报告,交付以下异常:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1109)
at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:399)
at android.app.Activity.onBackPressed(Activity.java:2066)
at android.app.Activity.onKeyUp(Activity.java:2044)
at android.view.KeyEvent.dispatch(KeyEvent.java:2529)
at android.app.Activity.dispatchKeyEvent(Activity.java:2274)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1855)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1277)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.widget.TabHost.dispatchKeyEvent(TabHost.java:297)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1855)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1277)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1803)
at android.view.ViewRoot.deliverKeyEventPostIme(ViewRoot.java:2880)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2853)
at android.view.ViewRoot.handleMessage(ViewRoot.java:2028)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4028)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:844)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
at dalvik.system.NativeStart.main(Native Method)

显然这与FragmentManager有关,而我并不使用它。堆栈跟踪没有显示任何我自己的类,所以我不知道这个异常发生在哪里以及如何防止它。

为了记录:我有一个tabhost,在每个选项卡中都有一个在活动之间切换的ActivityGroup。


当前回答

如果你继承FragmentActivity,你必须调用onActivityResult()中的超类:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    ...
}

如果你不这样做,并试图在该方法中显示一个片段对话框,你可能会得到OP的IllegalStateException。(说实话,我不太明白为什么超级调用可以解决这个问题。onActivityResult()在onResume()之前被调用,所以它仍然不允许显示片段对话框。

其他回答

我得到这个异常时,我按下后退按钮取消意图选择器在我的地图片段活动。 我通过替换onResume(在那里我初始化片段)的代码来解决这个问题,onstart()和应用程序工作正常。希望能有所帮助。

请在这里检查我的答案。基本上我只需要:

@Override
protected void onSaveInstanceState(Bundle outState) {
    //No call for super(). Bug on API Level > 11.
}

不要在saveInstanceState方法上调用super()。这把事情搞砸了……

这是支持包中的一个已知错误。

如果你需要保存实例并添加一些东西到outState Bundle中,你可以使用以下方法:

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
    super.onSaveInstanceState(outState);
}

最后,正确的解决方案是(如评论所示)使用:

transaction.commitAllowingStateLoss();

当添加或执行导致异常的FragmentTransaction时。

简单有效的解决方案:

遵循简单的步骤

步骤

步骤1:在各自的片段中覆盖onSaveInstanceState状态。并从中移除super method。

 @Override
public void onSaveInstanceState( Bundle outState ) {

}  

2 .使用 fragmentTransaction.commitAllowingStateLoss ();

而不是fragmentTransaction.commit();而片段操作。

提供:IllegalStateException的解决方案

这个问题困扰了我很久,但幸运的是,我想出了一个具体的解决方案。这里有详细的解释。

使用commitAllowStateloss()可能会防止这种异常,但会导致UI不规范。到目前为止,我们已经了解到,当我们在Activity状态丢失后试图提交一个片段时,会遇到IllegalStateException—所以我们应该延迟事务,直到状态恢复。可以像这样简单地做

声明两个私有布尔变量

 public class MainActivity extends AppCompatActivity {

    //Boolean variable to mark if the transaction is safe
    private boolean isTransactionSafe;

    //Boolean variable to mark if there is any transaction pending
    private boolean isTransactionPending;

现在在onPostResume()和onPause中,我们设置和取消设置布尔变量isTransactionSafe。想法是只有当活动在前台时才标记事务安全,这样就不会有无状态的机会。

/*
onPostResume is called only when the activity's state is completely restored. In this we will
set our boolean variable to true. Indicating that transaction is safe now
 */
public void onPostResume(){
    super.onPostResume();
    isTransactionSafe=true;
}
/*
onPause is called just before the activity moves to background and also before onSaveInstanceState. In this
we will mark the transaction as unsafe
 */

public void onPause(){
    super.onPause();
    isTransactionSafe=false;

}

private void commitFragment(){
    if(isTransactionSafe) {
        MyFragment myFragment = new MyFragment();
        FragmentManager fragmentManager = getFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.frame, myFragment);
        fragmentTransaction.commit();
    }
}

-我们到目前为止所做的将从IllegalStateException保存,但我们的事务将丢失,如果它们在活动移动到后台后完成,有点像commitAllowStateloss()。为了解决这个问题,我们有一个isTransactionPending布尔变量

public void onPostResume(){
   super.onPostResume();
   isTransactionSafe=true;
/* Here after the activity is restored we check if there is any transaction pending from
the last restoration
*/
   if (isTransactionPending) {
      commitFragment();
   }
}


private void commitFragment(){

 if(isTransactionSafe) {
     MyFragment myFragment = new MyFragment();
     FragmentManager fragmentManager = getFragmentManager();
     FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
     fragmentTransaction.add(R.id.frame, myFragment);
     fragmentTransaction.commit();
     isTransactionPending=false;
 }else {
     /*
     If any transaction is not done because the activity is in background. We set the
     isTransactionPending variable to true so that we can pick this up when we come back to
foreground
     */
     isTransactionPending=true;
 }
}

将getFragmentManager()更改为getChildFragmentManager()。不要使用父FragmentManager,尽量使用self。