Dagger 2: Android Modules

Many of the articles I write tend to involve application structure or architectural design patterns; and one of the most recurring topics I tend to visit is that of dependency injection.

Dependency injection is probably one of the most important topics of modern application development, whilst often overlooked as a necessity, it allows us to build highly scalable, powerful applications and platforms.

Dependency inversion works seamlessly with many other design principles and in many ways facilitates them, most specifically single responsibility. Effective dependency injection is achieved by providing dependencies through the constructor, usually as interface types, thereby allowing the class in focus to not worry about the instantiation of these types. I’ve gone into further detail about this in my previous article Effective Dependency Injection.

In this article I’d like to go into detail about how to use Dagger 2 with Android, the current version of Dagger at the time of writing is 2.11-rc1 and I’ll be including some of the most recent features such as @ContributesAndroidInjector.

The biggest problem with how most people use Dagger in Android applications is due in part to how components are created, most often the Activity or Fragment will create the component and inject itself, and in some cases will even retain an instance of the component to retain it through orientation change which is not recommended!

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
((MyApplication) getContext().getApplicationContext())
.getApplicationComponent()
.myActivityComponentBuilder()
.myActivityModule(this)
.build()
.inject(this);
  super.onCreate(savedInstanceState);
}

This is not pretty.

Last year at Mobile Central Europe, Gregory Kick proposed a new way of using Dagger with Android, be employing the use of Multibindings to provide Subcomponents through the Application via interface definition.

This technique meant that we were able to reduce a cyclical dependency on the application, because we were now able to define this by using an interface to provide a builder that would in turn build a subcomponent for our activities.

Setting up this approach would mean handling a fair amount of boilerplate in your application class, activity class and would require a few more module and component classes. Moving on a few months and Google have proposed a formal specification for this approach with the provision of additional Android modules.

compile "com.google.dagger:dagger-android-support:2.11-rc1"
annotationProcessor "com.google.dagger:dagger-android-processor:2.11-rc1"

Dagger & Android relies on a new concept that evolved from the approach of using an ActivityComponent, wherein your components will extend AndroidInjector<T>. Your Dagger application will then know how to collect a set of Android injectors for each of appropriate Android elements, and the class considered the parent of your injected class will be considered as the Dispatcher for the AndroidInjector<T>.

In order to set-up your components in a fashion that allows Dagger to collect them, you must then create the necessary modules and subcomponents with the appropriate annotations and injection targets.

This subcomponent is responsible for injecting dependencies into the Android component in question, this can be an Activity, Fragment, Service, IntentService, or Application. Be sure to use the correct module when using Android elements from the support library, since one is provided for Android framework elements also.

@Subcomponent
public interface MyActivitySubcomponent extends AndroidInjector<MyActivity> {
  @Subcomponent.Builder
public abstract class Builder extends AndroidInjector.Builder<MyActivity> {
}
}

The sole responsibility of this module is to indicate the binding for the subcomponent and specify its target, one could argue this is a little duplicitous since the subcomponent must also do this but this is required to tell Dagger about the definition.

@Module(subcomponents = MyActivitySubcomponent.class)
abstract class MyActivityModule {
  @Binds
@IntoMap
@ActivityKey(MyActivity.class)
abstract AndroidInjector.Factory<? extends Activity> myActivityInjectorFactory(MyActivitySubcomponent.Builder builder);
}

Be sure not to provide any dependencies for the subcomponent here since this module will be included in the application component and could thereby have application scope.

You can observe here how Dagger is building its internal graph here, since it’s using the Binds annotation to provide an implementation of AndroidInjector.Factory for MyActivity. Notice how the generic parameter on the method uses “? extends Activity” instead of your activity specifically, this is so Dagger can build a Map of these factories in your application class.

@Component(
modules = {
AndroidSupportInjectionModule.class,
MyActivityModule.class
}
)
interface MyApplicationComponent {
}

This final step is to include the module in your application component so that it is included in your application graph.

This was a tad tricky to set-up with a fair amount of knowledge required about how to build a dependency graph specific to Dagger 2.

This is why the folks at Google have provided a new way of implementing this, by using @ContributesAndroidInjector, Dagger will generate these classes for you, instead you only need to specify an abstract bind method in your application module…

AndroidBindingModule

abstract class AndroidBindingModule {
  @ContributesAndroidInjector
abstract MyActivity myActivity();
}

MyAppComponent

@Component(modules = {
AndroidSupportInjectionModule.class,
AndroidBindingModule.class
})
interface MyAppComponent extends AndroidInjector<MyApp> {
@Component.Builder
abstract class Builder extends AndroidInjector.Builder<MyApp>{
}
}

MyApplication

MyApplication extends DaggerApplication {
@Override
protected AndroidInjector<? extends DaggerApplication> injector(){
return DaggerMyAppComponent.builder().create(this);
}
}

tl;dr

  • Extend from DaggerApplication to inject the necessary dispatchers
  • Include AndroidSupportInjectionModule.class in your app component
  • Create a bind method annotated with @ContributesAndroidInjector

If you’d like to check out how to implement that, go take a look at my sample repository here!

Fun fact! This application is also a parody application based on the What-If web comic #34 by Randal Munroe. You can also download it from the Play store.