Lesson Wednesday

In the main lesson on DialogFragments, we explored creating a DialogFragment with a custom layout, overriding the onCreateView() method to do so. This is a common (and useful) way to interact with your users. Not every DialogFragment needs a custom layout, however, especially if you don't have to interact with its views. In many cases, it will suffice to have a title, a short text, and a yes/no button confirmation:

dialog-builder-standard.png

For this dialog, I supplied no unique layout, but instead built it with a Builder. The Builder design pattern is very common, and is essentially a way to build a complex object utilizing other subobjects and helper methods.

Introducing: Builder classes

Very briefly, let’s say we have an Animal object type (yes, I know that this is an unscientific term. Bear with me - get it?). Now let’s say that we wanted to build an instance. But what kind of animal? Animals vary so incredibly widely - from habitat to size to number of appendages to diet to lifespan to reproduction and a million other ways. Consider the difference between a duck and a spider. Both are animals in the broadest sense. But a lot of data that might have a property for spider (say: venomous = true) is impossible to map onto the properties of a duck, because they are quite profoundly different. Now if we add in the difference between chimpanzee and an owl, or a blue whale and a termite, then the complexity of difference becomes pretty boggling. There would be about a million properties that might be null for many of the potential Animals we might build.

One solution would be to write many different constructors in order to build any possible kind of Animal, but that becomes inefficient very quickly. We also don't want a ton of different constructors clogging up our code. Protecting against code rot (imagine adding a new global property, say "endangered" that wasn't present in the original spec to all of those constructors...!) would be a nightmare. We need a better way.

If the above example is too cerebral for you, imagine the builder as sandwich maker. You tick all the appropriate boxes on your order form: bread type, meat, cheese, condiments - and the sandwich maker makes it according to your specs. You can leave out the meat, even leave out the toppings if you like, the sandwich maker still knows how to make you a meal.

A builder class further abstracts the process of creating complex Objects for us, and we don’t worry too much about how it’s done.

There are many articles online on the topic of builders, but if you are looking for a primer, check out this article by Jose Luis Ordiales. It’s quick and easy to follow.

How to implement a builder

Let’s take a first look at the code I wrote to create the dialog above.

Here is my class:

MoodDialogFragment.java
public class MoodDialogFragment extends DialogFragment{

   @Override
   public Dialog onCreateDialog(Bundle savedInstanceState) {
       AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
       builder.setTitle("Dialog via Builder");
       builder.setMessage("Would you like to take a survey?");

       builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
           @Override
           public void onClick(DialogInterface dialog, int which) {
               dismiss();
           }
       });

       builder.setNegativeButton("Nope", new DialogInterface.OnClickListener() {
           @Override
           public void onClick(DialogInterface dialog, int which) {
               dismiss();
           }
       });

       return builder.create();
   }

}

Super short, super concise. Perfect.

Let’s go through this briefly.

First, I make a new builder object that is knowledgeable in the art of building AlertDialogs and their variants: AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

Second, I use some simple methods with supplied arguments to affect how the builder builds the object when I finally tell it to start building. These methods are predefined in the builder class - check this reference to see a complete list of available methods.

Third, I define some actions I want to take when a button is clicked - these take the form of callbacks (try and read them as if they were jQuery if you are having trouble understanding how they work.) I can set positive, negative, and neutral buttons.

When I’m done setting my settings, all I need to do is tell the builder to “go build!” and it will craft me a dialog window that is exactly how I set it up to be. Nice!