79

I started using DialogFragment, because they are working nicely through orientation changes, and stuff. But there is nasty problem I encountered.

I have AsyncTask that shows progress DialogFragment and dismisses it onPostExecute. Everything works fine, except when onPostExecute happens while application is in background (after pressing Home button, for example). Then I got this error on DialogFragment dismissing - "Can not perform this action after onSaveInstanceState". Doh. Regular dialogs works just fine. But not FragmentDialog.

So I wonder, what is the proper way of dismissing DialogFragment while application is in background? I haven't really worked with Fragments a lot, so I think that I'm just missing something.

Sver
  • 3,349
  • 6
  • 32
  • 53
  • see also [here](http://stackoverflow.com/questions/7992496/how-to-handle-asynctask-onpostexecute-when-paused-to-avoid-illegalstateexception) for nice solution using a paused handler – PJL Apr 23 '12 at 09:12

5 Answers5

168

DialogFragment has a method called dismissAllowingStateLoss()

Piyush
  • 18,895
  • 5
  • 32
  • 63
Jiang Qi
  • 4,450
  • 3
  • 19
  • 19
  • 16
    This only works if you use: [`show(FragmentManager, tag)`](http://developer.android.com/reference/android/app/DialogFragment.html#show(android.app.FragmentManager,%20java.lang.String)), but not when using [`show(FragmentTransaction, tag)`](http://developer.android.com/reference/android/app/DialogFragment.html#show(android.app.FragmentTransaction,%20java.lang.String)) because `popBackStack` in `dismissInternal` calls `enqueueAction(..., allowStateLoss=false)` even though we asked for allowing state loss. And it does this in both framework and support versions. – TWiStErRob May 05 '15 at 12:31
  • not working for me – thecr0w Jul 21 '23 at 10:40
10

This is what I did (df == dialogFragment):

Make sure that you call the dialog this way:

df.show(getFragmentManager(), "DialogFragment_FLAG");

When you want to dismis the dialog make this check:

if (df.isResumed()){
  df.dismiss();
}
return;

Make sure that you have the following in the onResume() method of your fragment (not df)

@Override
public void onResume(){
  Fragment f = getFragmentManager().findFragmentByTag("DialogFragment_FLAG");
  if (f != null) {
    DialogFragment df = (DialogFragment) f;
    df.dismiss();
  }
  super.onResume();
}   

This way, the dialog will be dismissed if it's visible.. if not visible the dialog is going to be dismisded next the fragment becomes visible (onResume)...

Ryan Amaral
  • 4,059
  • 1
  • 41
  • 39
  • This always dismisses the fragment when the user comes back, what if they didn't read the dialog yet, just left the app right after it is shown? – TWiStErRob May 05 '15 at 12:22
  • ```dismiss()``` already removes the dialog fragment internally. Source code: ```getFragmentManager().beginTransaction(); ft.remove(this);``` – Ryan Amaral Jul 23 '18 at 13:58
3

This is what I had to do to achieve what you want: I have a Fragment activity on which i was showing a dialog fragment named fragment_RedemptionPayment which is globally declared at the top. The following code dismisses the DialogFragment if it was showing before the activity goes in background and comes back in foreground.

     @Override
        public void onResume() {
            super.onResume();        
            if(fragment_RedemptionPayment.isVisible()){
                fragment_RedemptionPayment.dismiss();
            }
}
Vasily Kabunov
  • 6,511
  • 13
  • 49
  • 53
Shahid Sarwar
  • 1,209
  • 14
  • 29
2

Another new way of checking the state before calling dismiss is this:

if(!dialog.isStateSaved){
    dialog.dismiss()
} else {
    //Change the UI to suit your functionality
}

In this way its is checked that state is saved or not, basically on pause and onSaveInstanceState has been called.

For Java you can use isStateSaved()

KnowIT
  • 2,392
  • 1
  • 18
  • 16
0

A solution that might work is setting Fragment.setRetainInstance(true) in your dialogfragment, but that's not the prettiest of fixes.

Sometimes I have noticed that I have to queue up my dialog actions to let the framework restore the state first. If you can get hold of the current Looper (Activity.getMainLooper()) and wrap that in a Handler you could try passing your dismissal to the back of the queue by posting a runnable on that queue.

I often end up using a separate fragment that it retaininstance(true) that has a ResultReceiver. So i pass on that result receiver to my jobs and handle callbacks in its onReceive (often as a router for other receivers). But that might be a bit more work than it is worth if you are using async tasks.

Piyush
  • 18,895
  • 5
  • 32
  • 63
Sebastian Olsson
  • 836
  • 6
  • 10