Preface

If you’re familiar with creating newInstance() methods for Fragments, this is the same concept.

Imagine you are designing a general purpose Activity that will be called from multiple spots and with different configurations. How would you design this? Your first thought might be defining public constants like this:

public class CarActivity extends Activity {
    public static final String EXTRA_MAKE = "EXTRA_MAKE";
    public static final String EXTRA_MODEL = "EXTRA_MODEL";

    private String make;
    private String model;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        make = getIntent().getStringExtra(EXTRA_MAKE);
        model = getIntent().getStringExtra(EXTRA_MODEL);
    }

and then using them at the calling spot:

@Override
public void onClick(View view) {
    Intent intent = new Intent(view.getContext(), CarActivity.class);
    intent.putExtra(CarActivity.EXTRA_MAKE, "BMW");
    intent.putExtra(CarActivity.EXTRA_MODEL, "M5");
    view.getContext().startActivity(intent);
}

This works, but it’s fragile. One downside to Intents is they make tracing your code more difficult. You can still figure things out by searching for class usage and constant usage, however, it’s hard to ensure the correct types are being used since putExtra() hides them.

If I want to refactor the type of make from String to some custom enum that I’ve defined, I’ll need to manually verify that in all spots. Here’s a better approach:

public class CarActivity extends Activity {
    // These are private now since they are just an implementation detail at this point
    private static final String EXTRA_MAKE = "EXTRA_MAKE";
    private static final String EXTRA_MODEL = "EXTRA_MODEL";

    private String make;
    private String model;

    public static Intent buildIntentWithMakeAndModel(Context context, String make, String model) {
        Intent intent = new Intent(context, CarActivity.class);
        intent.putExtra(CarActivity.EXTRA_MAKE, make);
        intent.putExtra(CarActivity.EXTRA_MODEL, model);
        return intent;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        make = getIntent().getStringExtra(EXTRA_MAKE);
        model = getIntent().getStringExtra(EXTRA_MODEL);
    }

and then at the calling spot:

@Override
public void onClick(View view) {
    Intent intent = CarActivity.buildIntentWithMakeAndModel(view.getContext(), 
        "BMW", "M5");
    view.getContext().startActivity(intent);
}

The main benefit to this is that the types are enforced via the static method. I still have to verify that the types put in and taken out of the Intent match, but it’s much easier to do that in one spot. The static method is also much more descriptive than me stuffing the Intent at the calling spot.

Besides the type enforcement benefits, it also makes consuming your Activity easier. If there’s different combinations of Intent extras, the consumer no longer needs to figure them out, instead simply choose the correct static method! This is great when working on large teams, and it’s nice to always expect a method for building an Intent to be there.

I know this isn’t revolutionary, but hopefully it helps!