40

I'd like to make a dialog fragment that asks "Are you sure?" with a "yes/no" reply.

I've looked at the documentation and it's really verbose, going all over the place, explaining how to make advanced dialog boxes, but no intact code on making a simple 'hello world' kind of dialog box. Most tutorials utilize the deprecated dialog box system. The official blog seems to be unnecessarily complicated and difficult to understand.

So, what's the simplest way to create and display a really basic Alert Dialog? Bonus points if it's using the support library.

Muz
  • 5,866
  • 3
  • 47
  • 65

4 Answers4

80

A DialogFragment is really just a fragment that wraps a dialog. You can put any kind of dialog in there by creating and returning the dialog in the onCreateDialog() method of the DialogFragment.

Heres an example DialogFragment:

class MyDialogFragment extends DialogFragment{
    Context mContext;
    public MyDialogFragment() {
        mContext = getActivity();
    }
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(mContext);
        alertDialogBuilder.setTitle("Really?");
        alertDialogBuilder.setMessage("Are you sure?");
        //null should be your on click listener
        alertDialogBuilder.setPositiveButton("OK", null);
        alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });


        return alertDialogBuilder.create();
    }
}

To create the dialog call:

new MyDialogFragment().show(getFragmentManager(), "MyDialog");

And to dismiss the dialog from somewhere:

((MyDialogFragment)getFragmentManager().findFragmentByTag("MyDialog")).getDialog().dismiss();

All of that code will work perfectly with the support library, by just changing the imports to use the support library classes.

Robert
  • 6,855
  • 4
  • 35
  • 43
athor
  • 6,848
  • 2
  • 34
  • 37
  • Thanks, but seems to cause the error `Unable to instantiate fragment: make sure class name exists, is public, and has an empty constructor that is public` if I exit and re-enter the application while the dialog is open. Added an empty constructor, but then got a null pointer on mContext. – Muz Oct 17 '12 at 03:57
  • 8
    @muz The Android system requires a `Fragment` class to have a constructor with **no parameters** in order to instantiate the fragment when it needs to. In a `Fragment` you have a reference to the activity where this fragment is used with the method `getActivity()`(use it instead of `mContext`). Also the fragment must be declared in its own java file or as an **inner static** class in another class. Otherwise Android will not be able to find your fragment to instantiate it. – user Oct 17 '12 at 04:17
  • Yea sorry, I realised after posting the mContext and constructor there wasn't actually needed. Although it did work fine when I tested, I had the FragmentDialog in a inner static class. – athor Oct 17 '12 at 08:38
  • I think you must call the dismiss() method of the fragment instead of the dialog. – WindRider Dec 04 '13 at 12:42
12

So, what's the simplest way to create and display a really basic Alert Dialog? Bonus points if it's using the support library.

Simply create a DialogFragment(SDK or support library) and override its onCreateDialog method to return an AlertDialog with the desired text and buttons set on it:

public static class SimpleDialog extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new AlertDialog.Builder(getActivity())
                .setMessage("Are you sure?")
                .setPositiveButton("Ok", null)
                .setNegativeButton("No way", null)
                .create();
    }

}

To do something when the user uses one of the buttons you'll have to provide an instance of a DialogInterface.OnClickListener instead of the null references from my code.

ALXKAY
  • 21
  • 1
  • 7
user
  • 86,916
  • 18
  • 197
  • 190
5

For those coding with Kotlin and Anko, you can now do dialogs in 4 lines of code:

alert("Order", "Do you want to order this item?") {
    positiveButton("Yes") { processAnOrder() }
    negativeButton("No") { }
}.show()
Muz
  • 5,866
  • 3
  • 47
  • 65
2

because of Activity / Fragment lifecycle @athor & @lugsprog approach can fail, more elegant way is to **get activity context from method onAttach and store it as weak reference ** (&try to avoid non default constructor in DialogFragment!, to pass any argument to dialog use arguments) like this:

public class NotReadyDialogFragment extends DialogFragment {

    public static String DIALOG_ARGUMENTS = "not_ready_dialog_fragment_arguments";

    private WeakReference<Context> _contextRef;

    public NotReadyDialogFragment() {
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        /** example pulling of arguments */
        Bundle bundle = getArguments();
        if (bundle!=null) {
            bundle.get(DIALOG_ARGUMENTS);
        }

        //
        // Caution !!!
        // check we can use contex - by call to isAttached 
        // or by checking stored weak reference value itself is not null 
        // or stored in context -> example allowCreateDialog() 
        // - then for example you could throw illegal state exception or return null 
        //
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(_contextRef.get());
        alertDialogBuilder.setMessage("...");
        alertDialogBuilder.setNegativeButton("Przerwij", new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        return alertDialogBuilder.create();
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        _contextRef = new WeakReference<Context>(activity);
    }

     boolean allowCreateDialog() {
         return _contextRef !== null 
                && _contextRef.get() != null;
     }

EDIT: & if You wanna dismiss dialog then:

  1. try to get it
  2. check if it's exist
  3. check if it's showing
  4. dismiss

something like this :

        NotReadyDialogFragment dialog = ((NotReadyDialogFragment) getActivity().getFragmentManager().findFragmentByTag("MyDialogTag"));
    if (dialog != null) {
        Dialog df = dialog.getDialog();
        if (df != null && df.isShowing()) {
            df.dismiss();
        }
    }

EDIT2: & if u wanna set dialog as non cancelable u should change onCreatweDialog return statement like this:

    /** convert builder to dialog */
    AlertDialog alert = alertDialogBuilder.create();
    /** disable cancel outside touch */
    alert.setCanceledOnTouchOutside(false);
    /** disable cancel on press back button */
    setCancelable(false);

    return alert;
ceph3us
  • 7,326
  • 3
  • 36
  • 43
  • So I understand that calling `getActivity()` in the constructor can fail, but why would the solution suggested by Luksprog fail? Calling `getActivity()` in `onCreateDialog()` is exactly what the default implementation does, storing my own reference to the context sounds like the opposite of what I want to be doing. – Thorbear Feb 21 '17 at 13:54
  • @Thorbear getActivity() could return null when fragment is not attached to activity - you can use it but you should check it - sam for example using getResources() in fragment while fragment is not attached – ceph3us Feb 25 '17 at 07:25
  • Yes, and usually (always) the fragment is not attached when the constructor is being called. But is there any situation where `onCreateDialog()` will be called while the fragment is not attached? Again, the default implementation (the support library) calls `getActivity()` in `onCreateDialog()` without checking for null, are you saying that it should? – Thorbear Feb 27 '17 at 08:41