November 5, 2016 / Reading time: 2m

[AndroidBits] How to decouple navigation between your components

android

android-bits

The awesome static factory pattern for Android.

Note: If you are looking for a “How-To” pass data between your Android components, I’ve written a small article explaining.
[AndroidBits] Passing data in Android
My personal website and blog

Decoupled communication

Starting a new activity in Android requires calling startActivity(), you must pass an Intent as a parameter the framework knows the desired action.

This intent can receive data (as extras) and the associated component class e.g. Activity.

Intent intent = new Intent(this, MyActivity.class);
intent.putExtra("keyFoo", foo);
startActivity(intent);

Looking at the snippet, it’s easy to see the inherent coupling. If for some reason, the initial process/logic of MyActivity changes and requires a change on each instantiation throughout the whole code base, you’re screwed.

Also if data needs to be passed both the created, and instantiating classes must have a reference to the same key(s) (string) to each intent’s extra, you may end up with a helper/static class with all these key values as a simple solution but, in reality, it’s just unnecessary boilerplate code to maintain for something as simple as changing activities.

Enter the Static Factory Pattern

Static factory methods are simple wrappers that encapsulate what you need to pass when instantiating a new component.

private static final String EXTRA_SOME_TEXT = "someText";
private static final String EXTRA_MY_CUSTOM_OBJECT = "myCustomObject";

public class MyActivity extends AppcompatActivity {
  ...
  // Static factory method  
  public static Intent newStartIntent(Context context, String someText, SomeCustomObject myCustomObject) {
          Intent intent = new Intent(context, MyActivity.class);
          intent.putExtra(EXTRA_SOME_TEXT, someText);
          intent.putExtra(EXTRA_MY_CUSTOM_OBJECT, myCustomObject);
          return intent;
  }
  ...
}

The example gist shows how you can encapsulate you data in a static context (which means you can call this without having an actual instance) and use this method to instantiate MyActivity. As a bonus you could even make the MyActivity constructor(s) private, this will ensure the factory method is the only way to instantiate.

Now whenever MyActivity needs to be instantiated just call the factory method like this:

// Activity A instantiating "MyActivity"
startActivity(MyActivity.newStartIntent(this, "Hello World", awesomeCustomObject));

Another cool tip I heard on the Fragmented Podcast (ep. 14) is throwing an exception on that private constructor, if for some odd reason one of your team-mates go around the factory method he will be informed that’s isn’t the intended way to instantiate 😉.

private SomeObject() {
  throw new IllegalStateException("You should be using the Static factory method!")
}

This pattern can be applied to other components, it isn’t specifically for Activities. In fact, the Android fragment has a newInstance() method that follows this same static factory pattern just type “newInstance” on Android Studio and it should pop-up as a suggestion.

That’s it, Happy coding!✌️

Share