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

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。


当前回答

我最终创建了一个基本片段,并使我的应用程序中的所有片段扩展它

public class BaseFragment extends Fragment {

    private boolean mStateSaved;

    @CallSuper
    @Override
    public void onSaveInstanceState(Bundle outState) {
        mStateSaved = true;
        super.onSaveInstanceState(outState);
    }

    /**
     * Version of {@link #show(FragmentManager, String)} that no-ops when an IllegalStateException
     * would otherwise occur.
     */
    public void showAllowingStateLoss(FragmentManager manager, String tag) {
        // API 26 added this convenient method
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (manager.isStateSaved()) {
                return;
            }
        }

        if (mStateSaved) {
            return;
        }

        show(manager, tag);
    }
}

然后,当我试图显示一个片段时,我使用showAllowingStateLoss而不是show

是这样的:

MyFragment.newInstance()
.showAllowingStateLoss(getFragmentManager(), MY_FRAGMENT.TAG);

我从这个PR上找到了这个解决方案:https://github.com/googlesamples/easypermissions/pull/170/files

其他回答

简单有效的解决方案:

遵循简单的步骤

步骤

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

 @Override
public void onSaveInstanceState( Bundle outState ) {

}  

2 .使用 fragmentTransaction.commitAllowingStateLoss ();

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

每当你试图在你的活动中加载一个片段时,请确保活动处于恢复状态,而不是进入暂停状态。在暂停状态下,您可能会丢失已完成的提交操作。

你可以使用transaction.commitAllowingStateLoss()而不是transaction.commit()来加载片段

or

创建一个布尔值并检查activity是否不进入onpause状态

@Override
public void onResume() {
    super.onResume();
    mIsResumed = true;
}

@Override
public void onPause() {
    mIsResumed = false;
    super.onPause();
}

然后在加载片段时检查

if(mIsResumed){
//load the your fragment
}

我最终创建了一个基本片段,并使我的应用程序中的所有片段扩展它

public class BaseFragment extends Fragment {

    private boolean mStateSaved;

    @CallSuper
    @Override
    public void onSaveInstanceState(Bundle outState) {
        mStateSaved = true;
        super.onSaveInstanceState(outState);
    }

    /**
     * Version of {@link #show(FragmentManager, String)} that no-ops when an IllegalStateException
     * would otherwise occur.
     */
    public void showAllowingStateLoss(FragmentManager manager, String tag) {
        // API 26 added this convenient method
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (manager.isStateSaved()) {
                return;
            }
        }

        if (mStateSaved) {
            return;
        }

        show(manager, tag);
    }
}

然后,当我试图显示一个片段时,我使用showAllowingStateLoss而不是show

是这样的:

MyFragment.newInstance()
.showAllowingStateLoss(getFragmentManager(), MY_FRAGMENT.TAG);

我从这个PR上找到了这个解决方案:https://github.com/googlesamples/easypermissions/pull/170/files

我认为使用transaction.commitAllowingStateLoss();不是最好的解决方案。 当活动的配置改变,并且片段onSavedInstanceState()被调用,然后您的异步回调方法尝试提交片段时,将抛出此异常。

简单的解决方案是检查活动是否正在改变配置

例如:检查isChangingConfigurations()

i.e.

如果(! isChangingConfigurations ()) { / /提交事务。 }

签出这个链接

Fragment事务不应该在Activity.onStop()之后执行! 检查你没有任何回调可以在onStop()之后执行事务。最好是修复原因,而不是尝试使用.commitAllowingStateLoss()等方法来绕过问题。