0

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?

ThanosFisherman
  • 5,626
  • 12
  • 38
  • 63

3 Answers3

1

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
    }
}
Kevin Coppock
  • 133,643
  • 45
  • 263
  • 274
  • 1
    The first easiest solution didn't work for me. But the other two did plus a new one I just discovered right now. I will post an answer for that. and accept yours as the correct. Thanks! – ThanosFisherman Oct 17 '15 at 03:15
0

I will also like to add something I just discovered. If I switch the getSupportFragmentManager() on my existing code with getSupportFragmentManager().beginTransaction() it works fine. Code below

   protected void showDialog(final DialogFragment diag)
    {
        cancelDialog();
        if (diag != null && !diag.isAdded())
            diag.show(getSupportFragmentManager().beginTransaction(), "dialog");
    }

No idea why this works as I want to.

ThanosFisherman
  • 5,626
  • 12
  • 38
  • 63
  • That is incredibly strange. I can't imagine why that would make any difference, looking at the source for the two methods. Glad you got a working solution, though. :) – Kevin Coppock Oct 17 '15 at 03:26
  • I actually saw that workaround in another similar question while browsing here on stackOverflow (I don't have the link). So I guess it just works! – ThanosFisherman Oct 17 '15 at 03:29
  • What phone are you testing on? Just tried it on a Nexus 6 and it crashes either way for me. – Kevin Coppock Oct 17 '15 at 03:40
  • And using the first solution I mentioned above does work for me. I wonder if it's related to the fact that you seem to be reusing a dialog. Perhaps it's in some unexpected state? I'd suggest just showing a new instance of the dialog. – Kevin Coppock Oct 17 '15 at 03:42
  • maybe you are right ^^ Sadly I'm trying this on android emulator. I don't have an android 6 device. I think my current code structure is what makes things acting weird. I Just tried a few changes in my code and your first solution also worked – ThanosFisherman Oct 17 '15 at 03:45
-1

Showing a dialog after the user click on deny is not what guidelines said. You should show the permission rational only before a second request. You can look here for an automatic management: Permission library

greywolf82
  • 21,813
  • 18
  • 54
  • 108