I have got exception when ft.commit()
and I don't know why.
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1448)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1466)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:634)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:613)
at MainActivity.attachFragment(MainActivity.java:242)
at MainActivity.attachFragment(MainActivity.java:225)
at MainActivity.showHome(MainActivity.java:171)
at MainActivity.onComplete(MainActivity.java:278)
at MDownloadManager.onDownloadComplete(MDownloadManager.java:83)
at DownloadRequestQueue$CallBackDelivery$2.run(DownloadRequestQueue.java:61)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:149)
at android.app.ActivityThread.main(ActivityThread.java:5257)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:609)
at dalvik.system.NativeStart.main(NativeStart.java)
Here is my method where crash is comming.
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if(addToBackStack) {
ft.addToBackStack(null);
ft.add(R.id.frame_container, fragment, tag);
} else {
ft.replace(R.id.frame_container, fragment, tag);
}
ft.commit();
Have you got any idea what is wrong?
I don't use onSaveInstanceState
in my project.
Complete solution at Solution for IllegalStateException
Overriding onSaveInstanceSate is a hack which doesnt necessarily work for all the scenerios. Also using commitAllowingStateLoss() is dangerous and could lead to UI irregularities.
We need to understand that IllegalStateException is encountered when we try to commit a fragment after the Activity state is lost - Activity is not in foreground (to understand more about Activity states read this). Therefore to avoid (resolve) this exception we just delay our fragment transaction until the state is restored
Declare two private boolean variables
public class MainActivity extends AppCompatActivity {
//Boolean variable to mark if the transaction is safe
private boolean isTransactionSafe;
//Boolean variable to mark if there is any transaction pending
private boolean isTransactionPending;
Now in onPostResume() and onPause we set and unset our boolean variable isTransactionSafe. Idea is to mark trasnsaction safe only when the activity is in foreground so there is no chance of stateloss.
/*
onPostResume is called only when the activity's state is completely restored. In this we will
set our boolean variable to true. Indicating that transaction is safe now
*/
public void onPostResume(){
super.onPostResume();
isTransactionSafe=true;
}
/*
onPause is called just before the activity moves to background and also before onSaveInstanceState. In this
we will mark the transaction as unsafe
*/
public void onPause(){
super.onPause();
isTransactionSafe=false;
}
private void commitFragment(){
if(isTransactionSafe) {
MyFragment myFragment = new MyFragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.frame, myFragment);
fragmentTransaction.commit();
}
}
What we have done so far will save from IllegalStateException but our transactions will be lost if they are done after the activity moves to background, kind of like commitAllowStateloss(). To help with that we have isTransactionPending boolean variable
public void onPostResume(){
super.onPostResume();
isTransactionSafe=true;
/* Here after the activity is restored we check if there is any transaction pending from
the last restoration
*/
if (isTransactionPending) {
commitFragment();
}
}
private void commitFragment(){
if(isTransactionSafe) {
MyFragment myFragment = new MyFragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.frame, myFragment);
fragmentTransaction.commit();
isTransactionPending=false;
}else {
/*
If any transaction is not done because the activity is in background. We set the
isTransactionPending variable to true so that we can pick this up when we come back to
foreground
*/
isTransactionPending=true;
}
}
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