I sometimes see the following stacktrace for a commit that can happen when the user isn't looking at the activity (after state's been saved):
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1327)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1338)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
Looking at the Android source, this makes total sense:
private void checkStateLoss() {
if (mStateSaved) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
if (mNoTransactionsBecause != null) {
throw new IllegalStateException(
"Can not perform this action inside of " + mNoTransactionsBecause);
}
}
Now, I wonder if there is any way (besides storing a class variable in on(Save/Restore)InstanceState) to check if a fragment is going to be committed in an undesirable state, this way I can store the transaction for later and make the commit at the appropriate time.
Step 1: Create a New Project To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Step 2: Right-click on the First button inside java, then click on New. Step 2: Then Go to Fragment. Step 3: (The next step is to choose the Fragment type.
Android app must have an Activity or FragmentActivity that handles the fragment. Fragment can't be initiated without Activity or FragmentActivity.
Starting from support library version 26.0.0 Beta 1 a new API is available in FragmentManager
and Fragment
classes:
FragmentManager and Fragment have an isStateSaved() method to allow querying whether or not a transaction will be allowed without state loss. This is especially useful to check when handling an onClick() event before executing any transaction.
From docs of android.support.v4.app.FragmentManager#isStateSaved()
:
Returns true if the FragmentManager's state has already been saved by its host. Any operations that would change saved state should not be performed if this method returns true. For example, any popBackStack() method, such as popBackStackImmediate() or any FragmentTransaction using commit() instead of commitAllowingStateLoss() will change the state and will result in an error.
This API will ship with framework's android.app.FragmentManager
starting from Android O.
Since you did not attach any example code, all i can guess is that you're using "wrong" method when committing transaction.
so, instead of using FragmentTransaction.commit()
, you should use
FragmentTransaction.commitAllowingStateLoss().
Also, there are reports and workarounds about this issue (or rather change in API behavior) in this google blog post.
It is unluckily Android Fragment does not provide an API check if it is fine to commit transaction.
But we can add a boolean field in the attached activity helping us checking. Please ref the following code.
public class GlobalBaseActivity extends FragmentActivity {
private boolean mAllowCommit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAllowCommit = true;
}
@Override
protected void onSaveInstanceState(Bundle outState) {
mAllowCommit = false;
super.onSaveInstanceState(outState);
}
@Override
protected void onResumeFragments() {
mAllowCommit = true;
super.onResumeFragments();
}
public boolean allowFragmentCommit() {
return mAllowCommit;
}
public void callbackOnEvent() {
if (allowFragmentCommit()){
getFragmentManager().beginTransaction().add(new YourFragment(), TAG).commit();
}
}
}
As for why choosing onResumeFragment()
as allowing transaction indicator, ref this good blog. It explains famous IllegalStateException in detail.
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