I am using an AlertDialog in Android, asking the user for some input. I would like do run some code when the user has finished entering her input.

Since an AlertDialog is asynchronous, my code is not waiting for it. Therefore, I decided to use a callback, as in the following sample code:

This is the interface: AlertDialogCallback

public interface AlertDialogCallback<T>
{
}


The main activity implements the interface and calls the function creating the alert dialog:

public class MainActivity extends Activity implements AlertDialogCallback<String>

...

{
...
}

...



And the function creating the dialog has a final reference to the class that implements AlertDialogCallback (here MainActivity). It has to be final because of the nested anonymous class.

public static void askForInput(Context context, final AlertDialogCallback<String> callback)
{

// Set an EditText view to get user input
final EditText input = new EditText(context);

{
public void onClick(DialogInterface dialog, int whichButton)
{
String value = input.getText().toString();

}
});

{
public void onClick(DialogInterface dialog, int whichButton)
{
// Canceled.
}
});

}


I would like to know if this is a bad design (and why), and also if there is some kind of design pattern that is commonly used for this purpose in Android(/Java?).

Indeed the recommended approach for this (or at least what I would recommend) is to use callback interfaces.

The most important aspect though is designing this interface. In this case you should be sure that you're passing everything you need. However, I think you can rename the method to onOK or okPressed or similar. You might also consider returning a boolean to determine whether or not the dialog should really be closed (the input might need to be validated before it is accepted?) (there are ways to stop an AlertDialog from closing, you can find more information in earlier StackOverflow questions).

You should use String resources properly, this will separate the code from the text neatly. Use the resource id's instead.

alert.setTitle(R.string.alertInputTitle);


Some strings are actually included in Android by default, such as android.R.string.ok and android.R.string.cancel, use them when possible.

When you want the negative button to just close the dialog, you can actually pass null as the DialogInterface.OnClickListener.

alert.setNegativeButton(android.R.string.cancel, null);


Your pattern is close to what is recommended on the official Android dev network..

Formalizing your callback as an interface is the right choice, and passing an implementation of the interface to the dialog is also right. Where things differ is that the recommended practice works through the DialogFragment.

I can follow your code well enough, but, to follow the path-of-least-surprise, I would recommend tweaking it to be more standard. It should not be hard.

Note that the typical practice passes the whole DialogFragment back to the listener. This would work, and because the listener also built the fragment, it makes sense.... but, if your dialog is built in a place that's different to the listener, I would recommend a data container/Bundle instead.

• The link you posted there is not exactly about getting data from the dialog to the calling code, it's more about getting the data from the calling code (the dialog fragment) to the activity hosting the fragment. It is still a helpful link though, as some of the things still apply. You don't need a DialogFragment to show an AlertDialog though (even though it is often recommended to use Fragments). Overall, it's complicated :) – Simon Forsberg Jun 3 '14 at 15:07
• Is the DialogFragment preferable exclusively because it is more flexible, or does it have other advantages (e.g. is it more stable/safe than the AlertDialog)? – JonasVautherin Jun 3 '14 at 15:24
• The DialogFragment is built-populated by the Dialog-creating code. If the same code is passed the fragment back as a listener, then it is convenient as a data 'container'. It is only preferable because it is convenient. If the listener was not the same class that created the fragment, then a different container (Bundle) should be used. – rolfl Jun 3 '14 at 15:35