Any side effect to solve "Can not perform this action after onSaveInstanceState" by using commitAllowingStateLoss
android
Solution
The only thing I can think of, is kind of "race condition" event.
Imagine a situation, when device is being rotated just before your `commitAllowingStateLoss()` call. AFAIK, the following occurs:
- `onSaveInstanceState()` callback(activity store it's state with no fragment present at the moment(since you haven't committed anything yet)
- `commitAllowingStateLoss` is executed adding fragment to the activity
- `Activity` is recreated, restoring it's state to the moment, when there were no your fragment added
In my opinion, it cause hardly predictable situations, such as:
- `java.lang.IllegalStateException: Failure saving state: FragmentB has target not in fragment manager: FragmentA` if you are using `Fragment.setTargetFragment()` for any reason
- your fragment can simply be missing from the view
Anyway, I'm not 100% sure about that, but I'm having lots of unexpected `java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState` exceptions in my app, and trying to find a solution too.
Problem
Previously, we have no problem displaying the following `DialogFragment` ``` // Triggered by button click. private void openFromCloud() { LoadFromCloudTaskFragment loadFromCloudTaskFragment = new LoadFromCloudTaskFragment(); FragmentManager fm = this.getSupportFragmentManager(); fm.beginTransaction().add(loadFromCloudTaskFragment, "loadFromCloudTaskFragment").commit(); } ``` However, if we tend to display the same `DialogFragment` after pressing OK button on the following `Intent`, an error will occur. ``` private void openFromCloud() { startActivityForResult(Utils.getGoogleAccountCredential().newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER); } @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { switch (requestCode) { case REQUEST_ACCOUNT_PICKER: if (resultCode == RESULT_OK && data != null && data.getExtras() != null) { String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME); if (accountName != null) { Utils.getGoogleAccountCredential().setSelectedAccountName(accountName); LoadFromCloudTaskFragment loadFromCloudTaskFragment = new LoadFromCloudTaskFragment(); FragmentManager fm = getSupportFragmentManager(); fm.beginTransaction().add(loadFromCloudTaskFragment, "loadFromCloudTaskFragment").commit(); } } break; } } ``` Here are the detailed error log ``` FATAL EXCEPTION: main java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { (has extras) }} to activity {org.yccheok.xxx.gui/org.yccheok.xxx.gui.XXXFragmentActivity}: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at android.app.ActivityThread.deliverResults(ActivityThread.java:3141) at android.app.ActivityThread.handleSendResult(ActivityThread.java:3184) at android.app.ActivityThread.access$1100(ActivityThread.java:130) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1243) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4745) 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:786) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1299) at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1310) at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:541) at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:525) at org.yccheok.xxx.gui.XXXFragmentActivity$1.run(XXXFragmentActivity.java:107) at android.app.Activity.runOnUiThread(Activity.java:4591) at org.yccheok.xxx.gui.XXXFragmentActivity.onActivityResult(XXXFragmentActivity.java:102) at android.app.Activity.dispatchActivityResult(Activity.java:5192) at android.app.ActivityThread.deliverResults(ActivityThread.java:3137) ... 11 more ``` I can simply "solve" the problem by using `commitAllowingStateLoss` instead of `commit`. ``` fm.beginTransaction().add(loadFromCloudTaskFragment, "loadFromCloudTaskFragment").commitAllowingStateLoss(); ``` I don't really understand the documentation regarding `commitAllowingStateLoss`. 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. This is based on suggestion from getting exception "IllegalStateException: Can not perform this action after onSaveInstanceState" I don't really get the point it is okay for the UI state to change unexpectedly on the user.? May I know what is the possible side effect for using `commitAllowingStateLoss`? Any steps I can produce such side effect?