我有一个Live Android应用程序,从市场上我收到了以下堆栈跟踪,我不知道为什么它会发生,因为它不是发生在应用程序代码中,而是由应用程序的一些或其他事件引起的(假设)
我没有使用片段,仍然有一个FragmentManager的参考。
如果有人能揭示一些隐藏的事实,以避免这类问题:
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.onKeyDown(Activity.java:1962)
at android.view.KeyEvent.dispatch(KeyEvent.java:2482)
at android.app.Activity.dispatchKeyEvent(Activity.java:2274)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1668)
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.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:1720)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1258)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1668)
at android.view.ViewRoot.deliverKeyEventPostIme(ViewRoot.java:2851)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2824)
at android.view.ViewRoot.handleMessage(ViewRoot.java:2011)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4025)
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:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)
Android 4.2和支持库的源代码中修正了这个问题。[*]
有关原因(和解决方案)的详细信息,请参阅谷歌错误报告:
http://code.google.com/p/android/issues/detail?id=19917
如果你正在使用支持库,那么你不应该担心这个错误(很长时间)[*]。然而,如果你直接使用API(即不使用支持库的FragmentManager),并针对Android 4.2以下的API,那么你将需要尝试一种变通方法。
[*]在撰写本文时,Android SDK管理器仍在分发显示此错误的旧版本。
编辑,我要在这里补充一些澄清,因为我显然把投票反对这个答案的人弄糊涂了。
There are several different (but related) circumstances that can cause this exception to be thrown. My answer above is referring to the specific instance discussed in the question i.e. a bug in Android which has subsequently been fixed. If you're getting this exception for another reason it's because you're adding/removing fragments when you shouldn't be (after fragment states have been saved). If you're in such a situation then perhaps "Nested Fragments - IllegalStateException “Can not perform this action after onSaveInstanceState”" can be of use to you.
解决这个问题的另一种生命周期方法是使用kotlin最新发布的lifecycle-ktx。
lifecycleScope.launchWhenResumed {
// your code with fragment or dialogfragment
}
闭包将在恢复状态后运行,因此甚至在恢复状态后调用此方法
停,等下一份简历来的时候就安全执行了。
你也可以选择喜欢
lifecycleScope.launchWhenCreated
// or
lifecycleScope.launchWhenStarted
适合你的情况。
当销毁完成时,代码将被取消。
谷歌文档链接:
https://developer.android.com/kotlin/ktx#lifecycle
I noticed something very interesting. I have in my app the option to open the phone's gallery and the device asks what app to use, there I click on the gray area away from the dialog and saw this issue. I noticed how my activity goes from onPause, onSaveInstanceState back to onResume, it doesn't happen to visit onCreateView. I am doing transactions at onResume. So what I ended up doing is setting a flag being negated onPause, but being true onCreateView. if the flag is true onResume then do onCommit, otherwise commitAllowingStateLoss. I could go on and waste so much time but I wanted to check the lifecycle. I have a device which is sdkversion 23, and I don't get this issue, but I have another one which is 21, and there I see it.
这发生在你试图加载一个片段,但活动已改变其状态为onPause()。例如,当您试图获取数据并将其加载到活动中,但当用户单击某个按钮并移动到下一个活动时,就会发生这种情况。
你可以用两种方法解决这个问题
您可以使用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 fragment
}