Android “无法在 onSaveInstanceState 之后执行此操作”- 为什么我从活动的 onResume 方法中收到此异常?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12450024/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"Can not perform this action after onSaveInstanceState" - why am I getting this exception from my activity's onResume method?
提问by PacificSky
My activity invokes the camera with the ACTION_IMAGE_CAPTURE intent. If the camera activity returns succesfully, I set a flag in the onActivityResult callback, and based on the value of the flag I start a fragment in my onResume to add a caption to the image that was captured. This seems to work ok.
我的活动使用 ACTION_IMAGE_CAPTURE 意图调用相机。如果相机活动成功返回,我会在 onActivityResult 回调中设置一个标志,并根据该标志的值在我的 onResume 中启动一个片段,为捕获的图像添加标题。这似乎工作正常。
I just got a stack trace from the "wild" complaining that I was trying to commit a fragment transaction after onSaveInstanceState has been called. But I'm doing the commit in my onResume method! Why would android complain about this? I do have android:configChanges="orientation|keyboardHidden|keyboard|screenSize"set in my AndroidManifest.xml, so an orientation change should not trigger this....
我刚刚从“wild”那里得到了一个堆栈跟踪,抱怨我在 onSaveInstanceState 被调用后试图提交一个片段事务。但是我在我的 onResume 方法中进行提交!为什么android会抱怨这个?我确实在 AndroidManifest.xml 中设置了android:configChanges="orientation|keyboardHidden|keyboard|screenSize",因此方向更改不应触发此....
This occurred on a Samsung Galaxy S3 (SGH-i747) running 4.0.4
这发生在运行 4.0.4 的三星 Galaxy S3 (SGH-i747) 上
Here is the stack:
这是堆栈:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1314)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1325)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:548)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:532)
at com.Familiar.Android.FamiliarAppV1.AddPhotosActivity2.performFragmentTransition(AddPhotosActivity2.java:278)
at com.Familiar.Android.FamiliarAppV1.AddPhotosActivity2.switchToCaptionsFragment(AddPhotosActivity2.java:438)
at com.Familiar.Android.FamiliarAppV1.AddPhotosActivity2.onResume(AddPhotosActivity2.java:167)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1158)
at android.app.Activity.performResume(Activity.java:4544)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2448)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2486)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1187)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4514)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:747)
at dalvik.system.NativeStart.main(Native Method)
Any help or wisdom is appreciated.
任何帮助或智慧表示赞赏。
回答by PacificSky
I thinkI know the answer - I'm using the FragmentActivity from v4 compatibility library, and so I need to perform my fragment transactions in onResumeFragments instead of in onResume. Can someone confirm?
我想我知道答案 - 我正在使用 v4 兼容性库中的 FragmentActivity,所以我需要在 onResumeFragments 而不是 onResume 中执行我的片段事务。有人可以确认吗?
回答by Asaf Manassen
you can use the method commitAllowingStateLoss()
你可以使用这个方法 commitAllowingStateLoss()
but be aware you can lose the state of your activity as you can see in google's android referencewhich explain the different between the two in the following way
但请注意,您可能会丢失您的活动状态,正如您在 google 的android 参考中看到的那样 ,它通过以下方式解释了两者之间的不同
Like commit() but allows the commit to be executed after an activity's state is saved. This is dangerous because the commit can be lost if the activity needs to later be restored from its state, so this should only be used for cases where it is okay for the UI state to change unexpectedly on the user.
与 commit() 类似,但允许在保存活动状态后执行提交。这是危险的,因为如果活动稍后需要从其状态恢复,则提交可能会丢失,因此这应该仅用于 UI 状态可以在用户上意外更改的情况。
from my experience it may cause the addToBackStack
method not to work sometimes so you will need to add it manually on the fragment
and of course the state won't be saved (textbox text ext.)
根据我的经验,addToBackStack
有时可能会导致该方法不起作用,因此您需要在片段上手动添加它,当然不会保存状态(文本框文本扩展)。
回答by kurayami88
this worked for me... found this out on my own... hope it helps you!
这对我有用......我自己发现了这个......希望它对你有帮助!
1) do NOT have a global "static" FragmentManager / FragmentTransaction.
1) 没有全局“静态” FragmentManager / FragmentTransaction。
2) onCreate, ALWAYS initialize the FragmentManager again!
2) onCreate,总是再次初始化 FragmentManager!
sample below :-
下面的示例:-
public abstract class FragmentController extends AnotherActivity{
protected FragmentManager fragmentManager;
protected FragmentTransaction fragmentTransaction;
protected Bundle mSavedInstanceState;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSavedInstanceState = savedInstanceState;
setDefaultFragments();
}
protected void setDefaultFragments() {
fragmentManager = getSupportFragmentManager();
//check if on orientation change.. do not re-add fragments!
if(mSavedInstanceState == null) {
//instantiate the fragment manager
fragmentTransaction = fragmentManager.beginTransaction();
//the navigation fragments
NavigationFragment navFrag = new NavigationFragment();
ToolbarFragment toolFrag = new ToolbarFragment();
fragmentTransaction.add(R.id.NavLayout, navFrag, "NavFrag");
fragmentTransaction.add(R.id.ToolbarLayout, toolFrag, "ToolFrag");
fragmentTransaction.commitAllowingStateLoss();
//add own fragment to the nav (abstract method)
setOwnFragment();
}
}
回答by phlebas
UpdateI think I have found an explanation and a solution here: http://code.google.com/p/android/issues/detail?id=23096#c4I implemented the Empty Fragment Workaround posted there and got no more IllegalStateException so far.
更新我想我在这里找到了一个解释和一个解决方案:http: //code.google.com/p/android/issues/detail?id=23096#c4 我实现了发布在那里的 Empty Fragment Workaround 并且没有更多的 IllegalStateException 所以远的。
I add the invisible state fragment in my activity like this;
我像这样在我的活动中添加了不可见的状态片段;
@Override
protected void onCreate(final Bundle args) {
...
if (args == null) {
final FragmentManager fm = this.getSupportFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
final Fragment emptyFragmentWithCallback = new EmptyFragmentWithCallbackOnResume();
ft.add(emptyFragmentWithCallback, EmptyFragmentWithCallbackOnResume.TAG);
ft.commit();
}
The following code is taken from above link:
以下代码取自上述链接:
public class EmptyFragmentWithCallbackOnResume extends Fragment {
OnFragmentAttachedListener mListener = null;
@Override
public void onAttach(SupportActivity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentAttachedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnFragmentAttachedListener");
}
}
@Override
public void onResume() {
super.onResume();
if (mListener != null) {
mListener.OnFragmentAttached();
}
}
public interface OnFragmentAttachedListener {
public void OnFragmentAttached();
}
}
and invoke fragment transactions that would intuitively go into onResume or onResumeFragments into my custom onFragmentAttachedmethod that is invoked by the invisible state fragment. I do not use onResumeFragments at all and do not issue any fragment transactions in onResume.
并将直观地进入 onResume 或 onResumeFragments 的片段事务调用到我的自定义onFragmentAttached方法中,该方法由不可见的状态片段调用。我根本不使用 onResumeFragments,也不在 onResume 中发出任何片段事务。
So, to sum it up. If you are using the support lib and fragments, pretty much forget about onResume, forget about onResumeFragments and implement your own "onResume" based on the above workaround. This is somewhat ridiculous.
所以,总结一下。如果您正在使用支持库和片段,几乎忘记 onResume,忘记 onResumeFragments 并根据上述解决方法实现您自己的“onResume”。这有点荒谬。
I cannot confirm. I have the exact same problem. even though I am issuing fragment transaction in onResumeFragments. This used to work as I posted here: IllegalStateException - Fragment support library.
我无法确认。我有完全一样的问题。即使我在 onResumeFragments 中发出片段事务。这曾经像我在这里发布的那样工作:IllegalStateException - Fragment support library。
It seems the error only occurs on 4.0.3 and 4.0.4. However it does neither occur always nor in my Emulator.
似乎错误只发生在 4.0.3 和 4.0.4 上。然而,它既不会总是发生,也不会出现在我的模拟器中。
I am using support lib rev. 10 and API 16. I call DialogFragment.show in onResumeFragments and continously get this ridiculous exception from some random users. I cannot reproduce it locally.
我正在使用 support lib rev。10 和 API 16。我在 onResumeFragments 中调用 DialogFragment.show 并不断从一些随机用户那里得到这个荒谬的异常。我无法在本地重现它。
回答by Array
I was always getting this when I tried to show fragment in onActivityForResult() method, so the problem was next:
当我尝试在 onActivityForResult() 方法中显示片段时,我总是得到这个,所以接下来的问题是:
- My Activity is paused and stopped, which means, that onSaveInstanceState() was called already (for both pre-Honeycomb and post-Honeycomb devices).
- In case of any result I made transaction to show/hide fragment, which causes this IllegalStateException.
- 我的 Activity 被暂停和停止,这意味着 onSaveInstanceState() 已经被调用(对于蜂窝前和蜂窝后设备)。
- 如果出现任何结果,我进行了交易以显示/隐藏片段,这会导致此 IllegalStateException。
What I made is next:
我做的是下一个:
- Added value for determining if action I want was done (e.g. taking photo from camere - isPhotoTaken) - it can be boolean or integer value depending how much different transactions you need.
- In overriden onResumeFragments() method I checked for my value and after made fragment transactions I needed. In this case commit() was not done after onSaveInstanceState, as state was returned in onResumeFragments() method.
- 用于确定是否完成了我想要的操作的附加值(例如从相机拍摄照片 - isPhotoTaken) - 它可以是布尔值或整数值,具体取决于您需要多少不同的交易。
- 在覆盖 onResumeFragments() 方法中,我检查了我的价值,并在进行了我需要的片段交易之后。在这种情况下,在 onSaveInstanceState 之后没有执行 commit(),因为状态是在 onResumeFragments() 方法中返回的。
回答by Andre Rocha
I first develop my app targeting android 2.2 (SDK 8), using the support v4 library, and when I start using it with 4.2 (SDK 17), I had the same troubles with my fragments. But changing my Manifest to android:minSdkVersion="8" android:targetSdkVersion="17", solved my problems. Maybe this hepls you too.
我首先使用 support v4 库开发针对 android 2.2 (SDK 8) 的应用程序,当我开始将它与 4.2 (SDK 17) 一起使用时,我的片段也遇到了同样的问题。但是将我的清单更改为 android:minSdkVersion="8" android:targetSdkVersion="17",解决了我的问题。也许这对你也有帮助。
回答by Alok Singh
Add this to your Activity:
将此添加到您的活动:
@Override
protected void onSaveInstanceState(Bundle outState) {
//No call for super(). Bug on API Level > 11.
}