I had the original Nexus One when it first came out – fantastic phone at the time I think – and I’ve worked with Android development on and off for a few years. The system has gotten incrementally better over time, but I think the new  Architecture Components marketed as a part of Jetpack represent a major leap forward. Partly because they simplify some common issues and therefore reduce boilerplate, but mainly because they’re the first time Google has taken an opinionated view of architecture.

This is a good thing because Android architecture has been something of a wild west. Some solutions have been better than others, but the large variety of solutions is in itself expensive because it makes getting up to speed with a new code base more time consuming than if more aspects of the structure of apps had been standardized. As a side note, I think Spring is a great example of a framework that’s both opinionated and flexible enough to handle many different demands.

I thought I’d put together a small but complete app to test the new architecture components as well Googles guide to app architecture.

The Example App

The app will connect to the open  API of the Swedish Parliament and download a list of current and former Members of Parliament. Clicking an MP will opens a detail view of that MP. The app will use Retrofit for the API, Room for caching, ViewModel with LiveData and data binding to display data and Dagger for dependency injection.

Setting up Dagger 2

Dagger 2 isn’t part of Androids architecture components, but it is included although barely discussed in Googles guide to Android architecture, so I’m using it anyway. It does add some overhead in the form of boilerplate, extra libraries and time to learn. Weather or not the benefits outweigh the cost will depend on the project.

First we’ll create a Component, which is a class that injects dependencies described by modules. A Component can include multiple Modules (and normally does). A class instantiated as a singleton will be instantiated once per component.

It’s possible to have multiple Components, which can make sense to increase modularity, or because we want a singleton to be bound by a Component that belongs to some particular part of our system, such as an Activity.

To start with we’ll only add one module, the AndroidInjectionModule which belongs to the Dagger framework and simplifies the process of using Dagger to inject Android components like Activities. In order for this module to work, we also provide a method where our Application class can be injected.

@Singleton
@Component(modules = { AndroidInjectionModule.class })
public interface AppComponent {
    void inject(App app);
}

Continuing the boilerplate for Android injection, we need to extend our base Application class and have the extended class implement HasActivityInjector. Once we’ve done that we can use the Dagger component builder to inject our Application into the component graph.

public class App extends Application implements HasActivityInjector {
    private DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector;

    @Override
    public AndroidInjector<Activity> activityInjector() {
        return activityDispatchingAndroidInjector;
    }

    @Inject
    public void setActivityDispatchingAndroidInjector(DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector) {
        this.activityDispatchingAndroidInjector = activityDispatchingAndroidInjector;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        DaggerAppComponent
                .builder()
                .build()
                .inject(this);
    }
}

Now whenever we want to inject an Activity, we can create a module for the Activity that uses the @ContributesAndroidInjector annotation and provides our Activity. This module needs to be added to the Component we created above. I’m going to call the activity that displays a list of MPs, “MPListActivity”. 

@ContributesAndroidInjector
abstract MPListActivity provideMPListActivity();

In order to request Dagger to inject the activity, we add a method call to Dagger in our onCreate method before the call to super.

@Override
protected void onCreate(Bundle savedInstanceState) {
    AndroidInjection.inject(this);
    super.onCreate(savedInstanceState);
    ...
}

It’s quite a bit of boilerplate, but once it’s set up things get easier.

Example

As a quick example of usage, we could for instance use our module to describe how to inject a car.

@Provides
Car car(Engine engine) {
    return new Car(engine);
}

@Provides
Engine engine(){
    return new Engine();
}

As an alternative, we could annotate the constructors for Car and Engine with @Inject.

public class Car {
    private Engine engine;

    @Inject
    public Car(Engine engine) {
        this.engine = engine;
    }
}
public class Engine {
    @Inject
    public Engine() {
    }
}

Either way, we can then inject the car into our Activity.

@Inject
Car car;

With this boilerplate our of the way, let’s start building data layer in part 2.

Categories: android