55

I have a Fragment that can create and pop up a DialogFragment, but when I hit the back button, it dismisses the dialog even though I explicitly call setCancelable(false); Is there any way for my DialogFragment to be insensative to the back button?

public class LoadingDialogFragment extends DialogFragment
{
    String title;
    String msg;

    public LoadingDialogFragment()
    {
        this.title = "Loading...";
        this.msg = "Please wait...";
    }
    public LoadingDialogFragment(String title, String msg)
    {
        this.title = title;
        this.msg = msg;
    }

    @Override
    public Dialog onCreateDialog(final Bundle savedInstanceState)
    {
        final ProgressDialog dialog = new ProgressDialog(getActivity());

        dialog.setTitle(title);
        dialog.setMessage(msg);
        dialog.setIndeterminate(true);
        dialog.setCanceledOnTouchOutside(false);
        dialog.setCancelable(false);

        return dialog;
    }

}

I create the DialogFragment from an AsyncTask:

private class GpsTask extends AsyncTask<String, Integer, Integer>
{
    //ProgressDialog dialog;
    @Override
    protected void onPreExecute()
    {
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        DialogFragment newFragment = new LoadingDialogFragment("Gathering Location", "Acquiring GPS lock...");
        ft.addToBackStack(null);
        newFragment.show(ft, "dialog");
    }

    @Override
    protected Integer doInBackground(String... params)
    {
        //acquire a GPS lock and grab a few position updates
    }

    @Override
    protected void onProgressUpdate(Integer... input) { }

    @Override
    protected void onPostExecute(Integer result)
    {
        getSupportFragmentManager().popBackStackImmediate();
    }
}
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
MattF
  • 1,475
  • 3
  • 16
  • 18

5 Answers5

139

How about using setCancelable? Did you try it?

From the Docs:

Control whether the shown Dialog is cancelable. Use this instead of directly calling Dialog.setCancelable(boolean), because DialogFragment needs to change its behavior based on this

For custom DialogFragment

Add isCancelable = false at onCreateDialog

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Lalit Poptani
  • 67,150
  • 23
  • 161
  • 242
  • 42
    This is correct! it turns out you have to call setCancelable(false) on the DialogFragment itself, not the inner Dialog that it holds! – MattF Apr 16 '12 at 10:02
  • 2
    @MattF This comment is a life saver. Did not realize i needed to call `setCancelable()` on the `DialogFragment` instead of the `ProgressDialog`. Thanks! – prolink007 Sep 22 '15 at 15:40
  • 3
    I used `isCancelable = false` in Kotlin, inside of `onViewCreated` and it worked!! – Seven Feb 26 '19 at 22:09
  • It works for me too @Seven, i use isCancelable = false (not dialog.setCancelable(false)) – Fernando Perez Jul 19 '19 at 00:10
  • I was using ```getDialog.setCancelable(false)``` and it didn't work, but I replaced it with ```setCancelable(false)``` and it works correctly. that's was weird – Ehsan Dec 14 '19 at 12:43
  • For custom DialogFragment add isCancelable = false at onCreateDialog – Ashraf Amin Jul 07 '21 at 02:27
8
 DialogFragment newFragment = YourFragment.newInstance();
                newFragment.setCancelable(false);
                newFragment.show(fragmentTransaction, "dialog");

Add setCancelable(false) before you .Show() the fragment

Deejaygeekout
  • 232
  • 2
  • 5
  • GREAT tip. And here's an important further point on that http://stackoverflow.com/a/16480564/294884 – Fattie Jun 05 '14 at 08:19
4

I'm not at all sure if this'll work with FragmentDialogs, but if the setCancelable didn't work for you, it might be worth having a look at this article: Android: Prompt user to save changes when Back button is pressed

It explains how to detect the back button being pressed. So maybe you can suppress the button press and it'll stop the dialog from closing?

Community
  • 1
  • 1
manavo
  • 1,839
  • 2
  • 14
  • 17
3

onCreateDialog vs onCreateView:

Implementations should override this class and implement onCreateView(LayoutInflater, ViewGroup, Bundle) to supply the content of the dialog. Alternatively, they can override onCreateDialog(Bundle) to create an entirely custom dialog, such as an AlertDialog, with its own content.

Important when using onCreateDialog:

Override to build your own custom Dialog container. This is typically used to show an AlertDialog instead of a generic Dialog; when doing so, onCreateView(LayoutInflater, ViewGroup, Bundle) does not need to be implemented since the AlertDialog takes care of its own content.

Example Dialog (In this case an AlertDialog):

public static class MyAlertDialogFragment extends DialogFragment {

    public static MyAlertDialogFragment newInstance(int title) {
        MyAlertDialogFragment frag = new MyAlertDialogFragment();
        Bundle args = new Bundle();
        args.putInt("title", title);
        frag.setArguments(args);
        return frag;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        int title = getArguments().getInt("title");

        return new AlertDialog.Builder(getActivity())
                .setIcon(R.drawable.alert_dialog_icon)
                .setTitle(title)
                .setCanceble(false)
                .setPositiveButton(R.string.alert_dialog_ok,
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            ((FragmentAlertDialog)getActivity()).doPositiveClick();
                        }
                    }
                )
                .setNegativeButton(R.string.alert_dialog_cancel,
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            ((FragmentAlertDialog)getActivity()).doNegativeClick();
                        }
                    }
                )
                .create();
    }
} 

The property setCanceble(boolean) states whether you can exit the Dialog with a back press. No need to catch the KEYCODE_BACK anywhere.

DroidBender
  • 7,762
  • 4
  • 28
  • 37
  • 3
    This does not work. You have to call `setCancelable(boolean)` on the `DialogFragment`, not on the `Dialog` which is what you are doing now. – Daniel Mar 24 '14 at 18:03
3

It may help you.

newFragment.setCancelable(false); 

make changes like above when creating DialogFragment object or in the constructor of Custom DialogFragment as in the sample below.

public static CustomClearHourDialog newInstance(Bundle args, IDialogListener listener)
        {
            CustomClearHourDialog clearHourDialog = new CustomClearHourDialog();            
            CustomClearHourDialog.listener = listener;
            clearHourDialog.setCancelable(false);
            return clearHourDialog;
        }
Karthikeyan Ve
  • 2,550
  • 4
  • 22
  • 40