I get this error whenever I have my main activity with a fragment loaded and the user starts a new activity, switches the orientation of the device and comes back to main activity.
@Override
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.home_layout);
super.onCreate(savedInstanceState);
fragmentManager = getSupportFragmentManager();
fragment = fragmentManager.findFragmentById(R.id.layFragment);
initialize();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
setContentView(R.layout.home_layout);
initialize();
super.onConfigurationChanged(newConfig);
}
private void initialize() {
layStatus = (LinearLayout) findViewById(R.id.layStatus);
txtStatus = (TextView) findViewById(R.id.txtStatus);
....
handleFragments(lastFragmentId);
}
public void handleFragments(int fragmentId) {
if (fragment == null) {
FragmentTransaction ft = fragmentManager.beginTransaction();
if (fragmentId==someFragmentId){
ft.replace(R.id.layFragment, new FragmentSomeFragment());
}
else
....
ft.commit();
}
}
In my android manifest, the activity is declared as:
<activity
android:name=".HomeActivity"
android:configChanges="keyboardHidden|orientation" />
<activity
In another questions here on SO, I have found that this may be caused by a bug in Support library do I added without any luck:
// needed as a workaround for a bug in the Support library
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
super.onSaveInstanceState(outState);
}
My app runs from android 2.2 and I'm using the android-support-v4.jar Support library for fragments.
The log looks like:
07-27 11:56:20.399: E/AndroidRuntime(16021): FATAL EXCEPTION: main
07-27 11:56:20.399: E/AndroidRuntime(16021): java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
07-27 11:56:20.399: E/AndroidRuntime(16021): at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1299)
07-27 11:56:20.399: E/AndroidRuntime(16021): at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1310)
07-27 11:56:20.399: E/AndroidRuntime(16021): at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:541)
07-27 11:56:20.399: E/AndroidRuntime(16021): at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:525)
07-27 11:56:20.399: E/AndroidRuntime(16021): at com.rightcab.driver.core.HomeActivity.handleFragments(HomeActivity.java:341)
07-27 11:56:20.399: E/AndroidRuntime(16021): at com.rightcab.driver.core.HomeActivity.initialize(HomeActivity.java:128)
07-27 11:56:20.399: E/AndroidRuntime(16021): at com.rightcab.driver.core.HomeActivity.onConfigurationChanged(HomeActivity.java:153)
07-27 11:56:20.399: E/AndroidRuntime(16021): at android.app.ActivityThread.performConfigurationChanged(ActivityThread.java:3618)
07-27 11:56:20.399: E/AndroidRuntime(16021): at android.app.ActivityThread.handleActivityConfigurationChanged(ActivityThread.java:3771)
07-27 11:56:20.399: E/AndroidRuntime(16021): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1328)
07-27 11:56:20.399: E/AndroidRuntime(16021): at android.os.Handler.dispatchMessage(Handler.java:99)
07-27 11:56:20.399: E/AndroidRuntime(16021): at android.os.Looper.loop(Looper.java:137)
07-27 11:56:20.399: E/AndroidRuntime(16021): at android.app.ActivityThread.main(ActivityThread.java:4745)
07-27 11:56:20.399: E/AndroidRuntime(16021): at java.lang.reflect.Method.invokeNative(Native Method)
07-27 11:56:20.399: E/AndroidRuntime(16021): at java.lang.reflect.Method.invoke(Method.java:511)
07-27 11:56:20.399: E/AndroidRuntime(16021): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
07-27 11:56:20.399: E/AndroidRuntime(16021): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556)
07-27 11:56:20.399: E/AndroidRuntime(16021): at dalvik.system.NativeStart.main(Native Method)
First, as I can see, you want to handle configuration changes yourself. In order to let things to work properly with API Level 13+, you have to add one more value to configChanges
parameter, as described here.
Next, when the user leave your main activity, onSaveInstanceState
and onPause
methods are called for it. When the user rotates device and come back to your main activity. onConfigurationChanged
method is called before onResume()
. So, your activity is still paused and you cannot perform FragmentTransaction
.
Further more, if we take a look into source code we can see the following comment for onResume
method:
Dispatch onResume() to fragments. Note that for better inter-operation with older versions of the platform, at the point of this call the fragments attached to the activity are not resumed. This means that in some cases the previous state may still be saved, not allowing fragment transactions that modify the state. To correctly interact with fragments in their proper state, you should instead override {@link #onResumeFragments()}.
So, the right place to manipulate fragments in your activity is overriding onResumeFragments
method, as we can read in the comment for this method in source code:
This is the fragment-orientated version of {@link #onResume()} that you can override to perform operations in the Activity at the same point where its fragments are resumed. Be sure to always call through to the super-class.
protected void onResumeFragments() {
super.onResumeFragments();
// YOUR STUFF IS HERE
}
If as StenaviN suggests onConfigurationChange()
is being returned before resume() on coming back to your activity:
This is the lifecycle:
onCreate()
onResume()
// Move away from you're Activity
onPause()
// Move back to your Activity
onConfigurationChange()
onResume()
But the important part is this:
If you resume an Activity
or you change the Orientation
of an Activity
your Fragments
will be fine! You don't need to replace the old one with a new copy and in fact you shouldn't! If you simply remove this line you won't have a problem:
handleFragments(lastFragmentId);
however If you're doing this because you need your Fragment
to load a new layout resource (layout/frag.xml
=> layout-land/frag.xml
) then you're going to need to do something like this:
boolean mResumed = false;
onPause() {
mResumed = false;
}
onResume() {
mResumed = true;
}
...
if(mResumed) handleFragments(lastFragmentId);
Are you using the latest version of the support-v4 library? It fixed my similar problem.
If you are stuck to the version r7 of support library (for instance because you are using maven and desesperatly waiting for an update.. ;) ), then you can use onPostResume
to avoid this problem. If your version is r11 or above, then you can switch to onResumeFragements
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With