I'm trying to show a DialogFragment right after the user clicks "Deny" on the "allow/deny permission" dialog of android 6 But instead I'm getting this error:
Caused by: 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 android.support.v4.app.DialogFragment.show(DialogFragment.java:139)
at android.support.v4.app.FragmentActivity.onRequestPermissionsResult(FragmentActivity.java:802)
at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6553)
at android.app.Activity.dispatchActivityResult(Activity.java:6432)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3695)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742)
at android.app.ActivityThread.-wrap16(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
My dialog code is pretty standard
protected void showDialog(DialogFragment diag)
{
if (diag != null && !diag.isAdded())
diag.show(getSupportFragmentManager(), "dialog");
}
How can this be fixed?
So, there are a couple of solutions to this, none particularly pretty. What it means is that your Activity's FragmentManager is not yet in a valid state for committing FragmentTransactions in a safe manner (although in this particular case, it should always be.)
1) Use .commitAllowingStateLoss()
instead of .show()
:
This is the easiest fix, although I'm not entirely clear what differences arise by not using the .show()
methods, which set a few flags internally. Seems to work fine.
getSupportFragmentManager()
.beginTransaction()
.add(diag, "dialog")
.commitAllowingStateLoss();
1) Post the .show()
as a Runnable
on a Handler
:
// Initialize a Handler ahead of time and keep it around
private Handler mHandler = new Handler();
...
// after getting denied:
mHandler.post(new Runnable() {
@Override
public void run() {
// Show your dialog
}
}
...
@Override
protected void onStop() {
super.onStop();
// Clear out the Runnable for an unlikely edge case where your
// Activity goes to stopped state before the Runnable executes
mHandler.removeCallbacksAndMessages(null);
}
2) Set a flag and show the dialog in onResume()
private boolean mPermissionDenied;
@Override
public void onRequestPermissionsResult(...) {
// If denied...
mPermissionDenied = true;
}
@Override
protected void onResume() {
super.onResume();
if (mPermissionDenied) {
mPermissionDenied = false;
// Show your dialog
}
}