我有一个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)
解决这个问题的另一种生命周期方法是使用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.
I solved the issue with onconfigurationchanged. The trick is that according to android activity life cycle, when you explicitly called an intent(camera intent, or any other one); the activity is paused and onsavedInstance is called in that case. When rotating the device to a different position other than the one during which the activity was active; doing fragment operations such as fragment commit causes Illegal state exception. There are lots of complains about it. It's something about android activity lifecycle management and proper method calls.
To solve it I did this:
1-Override the onsavedInstance method of your activity, and determine the current screen orientation(portrait or landscape) then set your screen orientation to it before your activity is paused. that way the activity you lock the screen rotation for your activity in case it has been rotated by another one.
2-then , override onresume method of activity, and set your orientation mode now to sensor so that after onsaved method is called it will call one more time onconfiguration to deal with the rotation properly.
你可以复制/粘贴这段代码到你的活动来处理它:
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Toast.makeText(this, "Activity OnResume(): Lock Screen Orientation ", Toast.LENGTH_LONG).show();
int orientation =this.getDisplayOrientation();
//Lock the screen orientation to the current display orientation : Landscape or Potrait
this.setRequestedOrientation(orientation);
}
//A method found in stackOverflow, don't remember the author, to determine the right screen orientation independently of the phone or tablet device
public int getDisplayOrientation() {
Display getOrient = getWindowManager().getDefaultDisplay();
int orientation = getOrient.getOrientation();
// Sometimes you may get undefined orientation Value is 0
// simple logic solves the problem compare the screen
// X,Y Co-ordinates and determine the Orientation in such cases
if (orientation == Configuration.ORIENTATION_UNDEFINED) {
Configuration config = getResources().getConfiguration();
orientation = config.orientation;
if (orientation == Configuration.ORIENTATION_UNDEFINED) {
// if height and widht of screen are equal then
// it is square orientation
if (getOrient.getWidth() == getOrient.getHeight()) {
orientation = Configuration.ORIENTATION_SQUARE;
} else { //if widht is less than height than it is portrait
if (getOrient.getWidth() < getOrient.getHeight()) {
orientation = Configuration.ORIENTATION_PORTRAIT;
} else { // if it is not any of the above it will defineitly be landscape
orientation = Configuration.ORIENTATION_LANDSCAPE;
}
}
}
}
return orientation; // return value 1 is portrait and 2 is Landscape Mode
}
@Override
public void onResume() {
super.onResume();
Toast.makeText(this, "Activity OnResume(): Unlock Screen Orientation ", Toast.LENGTH_LONG).show();
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}