Dagger 2 Dependency Injection for Android Developers

Dagger 2 is a dependency injection library that relies heavily on annotation preprocessing to automatically generate a series of classes that provide dependencies to various parts of your application. The preprocessing occurs as part of compilation. The class files that are created are human readable — some are meant to be referenced just like any other java classes, others should just silently do their magic in the background.

The first iteration of Dagger was known for being highly effective on Android. The next generation of Dagger attempts to address some of the issues of the original Dagger. Some of the items addressed include generated classes that are easier to read, more compile time work/less runtime work, and scoping that allows for better object life cycles.

Some Background and Alternative Material

If you are not familiar with the concept of dependency injection, consider this short form video: https://youtu.be/IKD2-MAkXyQ (4:46), or this long form blog post: http://www.martinfowler.com/articles/injection.html

If you’d like some history on the why of Dagger 2, here is an explanation from the source: https://youtu.be/oK_XtfXPkqw (4o:15).

An excellent video presentation on Dagger 2 can be found here : [free | requires registration] https://www.parleys.com/tutorial/the-future-dependency-injection-dagger-2 (54:02). This blog post and the Parleys video cover most of the same topics. The video generally goes into more detail and describes more of the nuances of various concepts and API functionality for Dagger 2. This blog post is intended to be briefer, easier to skim, and favors those who prefer reading over watching a video.

The official source for Dagger 2, with some documentation of it’s own: http://google.github.io/dagger/.

Note: this blog post is heavily informed by the last two links.

While Reading The Code in this Post

In the code examples provided in this post, there are class names such as DependencyModule, DependencyImplementation, SecondaryDependency, and ParentComponent. This nomenclature are not actually part of the Dagger 2 API. The names are instead example class names. This was done intentionally to avoid feeling the need to manipulate the code snippets to conform to the context of real world examples.

The Basics of Dagger 2

There are two main aspects of working with Dagger 2: modules and components. Learning both concepts is required in order to use effectively use Dagger 2.

Constructing Dependencies

In order to provide dependencies, Dagger has to know how to construct them. We use the concept of modules to give dagger the means necessary for dependency construction. Modules are classes that create and provide these dependencies.

Modules

Dependencies used by your app should be divided into modules that makes sense. What makes sense depends on the problem space and usually consists of all the constituent parts of a cohesive subsystem — excluding parts to other subsystems. A cohesive subsystem quite often lives within a single package namespace.

Module classes are annotated with @Module. This annotation lets dagger know which classes are modules.

Modules provide their dependencies through public methods that return the classes they provide. Module methods that provide dependencies are annotated with @Provides. These providing methods are understood by Dagger to provide object for the type of class that those methods return.

Providing methods traditionally take the name format “provide[ProvidedClassName]”.

/**
* A module that provides parts of a given subsystem.
*/
@Module
public class SubsystemModule {
@Provides
public SubsystemPartOne provideSubsystemPartOne() {
return new SubsystemPartOneImplementation();
}
    @Provides
public SubsystemPartTwo provideSubsystemPartTwo() {
return new SubsystemPartTwoImplementation();
}
}

Modules often provide dependencies that they themselves use. This is done by having one providing method that provides a dependency that is needed by a second providing method. When a dependency has a secondary dependency, that secondary dependency should be provided as a parameter to the providing method that instantiates that primary dependency. Once this wiring is in place, Dagger will resolve dependencies in an appropriate order, creating and passing in these providing method parameter objects where needed.

@Module
public class DependencyModule {
    // The secondary dependency will be generated and passed in
// by dagger automatically.
@Provides
public Dependency provideDependency(
SecondaryDependency secondaryDependency) {
return new DependencyImplementation(secondaryDependency);
}
    // Dagger will construct the secondary dependency
// using this method.
@Provides
public SecondaryDependency provideSecondaryDependency() {
return new SecondaryDependencyImplementation();
}
}

It is possible to pass run-time parameters to Dagger modules so that they can be used to construct dependencies.

@Module
public class DependencyModule {
    public RuntimeParameter runtimeParameter;
    public DependencyModule(RuntimeParameter runtimeParameter) {
this.runtimeParameter = runtimeParameter;
}
    @Provides
public Dependency provideDepedency() {
return new Dependency(runtimeParameter);
}
}

Components and the Object Graph

The Object Graph

The process of resolving dependencies in order to resolve other dependencies eventually leads to a network of dependency resolutions. This network is known as an object graph. Dagger, along with other dependency injection libraries, are designed to allow objects to be requested out of this graph. When an object is requested, it’s dependencies are resolved — the object is constructed and handed back to the requestor.

In Dagger, modules often do not contain all the secondary dependencies needed to create the objects those modules provide. It is expected that other modules will fulfill these missing dependencies. We link modules to each other by grouping them in components. Modules in the same component can provide dependencies to each other.

Components are the objects that requestors contact for dependencies. Modules create instances of dependencies. Components provide those dependencies.

Component Definition

Components are written as interfaces whose methods provide dependencies. In this way, component encapsulate their modules and exposes only those dependencies available for use in those components.

Components are identified to dagger by the @Component annotation.

/**
* Provides a dependency out of module one.
*
* This is a case where ModuleOneDependency has a secondary
* dependency on a class provided by DependencyModulesTwo.
*
* The component ties the two modules together so that the
* secondary dependency can be resolved. The component then
* exposes the dependency it provides via method signature.
*/
@Component(modules = {
DependencyModuleOne.class,
DependencyModulesTwo.class
}
public interface DependencyComponent {
ModuleOneDependency moduleOneDependency();
}

When we compile code that supports Dagger, Dagger will generate component helper classes based on the interfaces defined by components.

All compiled helper class names will take the form Dagger[ComponentClassName]. The generated class will expose a builder that facilitates component construction. The example component in the code snippet above above would have a generated helper class of

DaggerDependencyComponent.class

This helper class with have a static public method named builder(). The builder() method will return a builder that will generate the component described in the component’s annotated interface.

DaggerDependencyComponent.builder()

The builder will have a method named after each module that the component contains. These methods will allow us to pass in instances of the modules that should be used to construct the component. Calling these methods is only necessary if the module being passed in requires runtime parameters (state) in order to be constructed.

// Creating a component from the dagger generated builder.
DependencyComponent dependencyComponent =
Dagger_DependencyComponent.builder()
.dependencyModuleTwo(
new DependencyModuleTwo(
RuntimeParameter runtimeParameter)
.build();
// Fetching dependencies out of the component.
ModuleOneDependency moduleOneDependency = dependencyComponent
.moduleOneDependency();

Automated Injection

[EDIT]The latest version(s) of Dagger 2 no longer seem to support this style of injection. Either that, or the implementation has changed.[EDIT]

In the code above, we collect dependencies out of components directly. Components also have the ability to assign dependencies directly upon a class.

By giving a member variable default (package) visibility with an object and then annotating it as an @Inject, we can make it available for automatic injection. We then need to update the component to accept the object for automated injection. Once we have the component and the object, we pass the object to the component and it will inject the dependency directly into the object.

@Component()
public interface DependencyComponent {
Dependency moduleOneDependency();
void inject(DependencyReceiver dependencyReciever);
}
public class DependencyReceiver {
@Inject Dependency dependency;
    public DependencyReceiver() {
...
}
}
public class ControllerClass {
    DependencyReceiver dependencyReceiver;
    public ControllerClass() {
DaggerDependencyComponent.Builder()
.build()
.inject(dependencyReceiver);
}

Classes can also be designed to use components to automatically inject dependencies into themselves. The limitation here is that dagger cannot inject dependencies from inside the constructor. Despite this limitation, the functionality is still particularly useful in certain system, such as Android.

public class DependencyReceiverActivity extends AppCompatActivity {
    @Inject
Dependency dependency;
    @Override
public void onCreate(Bundle savedInstanceState) {
DaggerDependencyComponent.Builder()
.build()
.inject(this);
}
}

Component Interactions

As I stated previously, components can provide dependencies for each other. There are two main mechanisms for coordinating components: subcomponents and dependencies. Both mechanism allow a sub, or secondary, component access to the dependencies provided by the primary component. The primary difference between the mechanism is in retrieval.

Subcomponents

Subcomponents are components that are derived from parent components. We define the subcomponent in the same way we do any component. We then add a provider method to the parent component. The provider method takes the subcomponents modules as paremeters.

@Component(
modules = {
...
}
)
public interface DependencyComponent {
DependencyOne dependencyOne();
DependencyTwo dependencyTwo();
DependencySubcomponent dependencySubcomponent(
DependencyModule dependencyModule);
}

When fetching dependencies out of a subcomponent, we must either request dependencies that are explicitly exposed by the subcomponent or we can use automated injection to have all dependencies injected that are in a subcomponent and any parent component.

public class DependencyReceiverActivity extends AppCompatActivity {
// comes from the subcomponent
@Inject
Dependency dependency;
// comes from the subcomponent's parent, even if not explicitly 
// exposed by the subcomponent's parent
@Inject
ParentComponentDependency ParentComponentDependency;
@Override
public void onCreate(Bundle savedInstanceState) {
DaggerDependencyComponent.Builder()
.build()
.subcomponent(DependencyModule module)
.inject(this);
}
}

One final note about subcomponents, they can be stacked to create complex component graphs. This means a component can be a subcomponent to a subcomponent. Using this mechanism, it is possible to create subcomponents, then release them once they are no longer needed. Dagger will allow them to fall out of scope and any object they contain directly will be garbage collected.

Components as Dependencies

Alternative to subcomponents, we can assign components as dependencies to other components. This is done within the @Component annotation.

@Component (
dependencies = {
ParentComponent.class
}
)
public interface Component {
ParentComponentProvidedDependency
parentComponentProvidedDependency();
}

The dependencies mechanism is more explicit than the subcomponents mechanism. This means we cannot receive dependencies from a component’s own dependencies unless that component explicitly exposes those dependencies. For those who like to be more explicit and control visibility, this approach provides the needed mechanisms.

Component dependencies can be stacked as well, so that a component that is a dependency for another component can also have it’s own dependencies. When using this explicit approach, you will have to create a provider method for each component up the component tree until you reach the component that has the module that creates the dependency.

Scopes

Scopes are primarily a validation mechanism that helps ensure that objects are created and broken down at the appropriate times. I will add scopes to this presentation soonerish. For now, you can check out my sample project on Github which has some basic scopes implementation: https://github.com/randallmitchell/todolist.