Android Dependency Injection using Dagger 2

Tompee Balauag
Familiar Android
Published in
6 min readApr 10, 2018
Photo by Nelly Volkovich on Unsplash

Update: Dagger for Android guide available here.

Update: Part 2 is now available here.

Dagger 2 is a dependency injection framework for Java that is very popular in the Android community. It was developed and maintained by Google as a successor of, you guessed it right, Dagger.

For those who are not familiar, dependency injection is a pattern in which the dependencies are provided to the object instead of finding and building it on its own. It is part of the umbrella concept Inversion of Control. Think of it as offloading dependency creation and management from your application and delegating it to a “service”.

Note: In this tutorial, we will not be using dagger-android.

First, let me show how manual dependency injection looks like. Consider these classes.

There is really nothing wrong with the above classes, but if you look at it on a testability and reusability perspective, you can argue that the warrior class is heavily coupled on the sword weapon. One way to fix this is to accept a weapon instance instead.

The above class looks much better since it is no longer dependent on a specific instance of a weapon class. The user can now pass different weapons. You can step it up a notch by using a weapon interface instead. This will allow you to mock the weapon implementation during testing, or use a different implementation of weapon altogether.

The above class uses constructor injection because dependencies are provided in the constructor. There are other types of injection such as field injection (dependencies are declared as public fields) and method injection.

Now, the user of this class will have to pass a weapon object. However, you don’t want to repeat your mistakes again and instantiate a weapon class in the user class. You might want to accept it as well from the upper layer. By building on this idea, you are now delegating the dependency creation at the uppermost layer. However, this is not ideal for us to do on our own since we will encounter a lot of problems such as complicated dependency graphs, cpu cycle and memory overhead when instantiating all our dependencies at once even without actually needing it.

Dependency injection frameworks come to the rescue.

A good dependency injection allows you to build your dependency graph, instantiate the dependencies lazily and manage their lifecycles automatically. And I believe Dagger 2 has all these features along with a lot of cool features as well.

When I started with Dagger 2, it wasn’t a eureka moment for me. I had to do a lot of reading and practicing before I got the hang of it. I’m still not a master of it but I can say I know the basics of it by heart to start this tutorial.

I think of dagger as a service that contains all of my dependency. I can ask for it myself or ask it to inject it for me. To understand dagger 2, you need to understand its annotations.

@Component Annotation

The component is the interface between the service and your application. It is an interface that dagger will implement. Oh did I mention that dagger generates implementation code for you? Convenient right?

As I mentioned, the component is an interface. It is also the dependency graph. It is also the container. It has a lot of functions. But for starters, think of it as the DI service interface. If you want any dependency from it, you should define it here. Take a look at the class below.

First thing you need to know is that a component is an interface or an abstract class. Second is that it should be annotated with @Component. The @Singleton is a scoping annotation. Scopes are out of scope (see what I did there?) of this tutorial but I will explain at least this special scope later.

Notice that I defined 2 functions, 1 that return a context and one that returns an application. This means when I have this component already instantiated in my app, I can do something like component.context or component.applicationContext to get my dependencies. Awesome right?

However, this will not work yet. It’s great that you have an interface and all but dagger does not really know (yet) where to get your dependencies, or how to provide them for you. To do that, you have to link modules.

@Modules annotation

Modules are what provide your dependencies. Your component must contain the modules that satisfies all of its exposed objects. Lets take a look at the example.

Modules are concrete classes that are annotated with @Module. The module methods are annotated with @Provides. This instructs dagger that this method returns an object that can be used by the component to satisfy other internal or external dependencies. Notice that the function names start with ‘provide’. This is just a convention. What is important is the return type.

In the class above, we are providing 2 objects, an application and a context. This satisfies the AppComponent requirements already. However, the module requires an instance of the application context that is why we will ask the user of this module to provide it for us. It is not wise to create a new context, since you are interested in the actual context of your application.

Now, we need to build our project first because dagger generates the code at compile time. After building, dagger will generate a new class from your component prepended with ‘Dagger’. Use this to build an instance of your component.

When instantiating a component, you need to use the builder and provide all the module dependencies of the component. In our example, we only depend on the AppModule that is why we need to instantiate an AppModule using our context and set it to the builder. Since we passed MyApplication context in AppModule, everytime the context or application instance is requested from it, it will always provide the MyApplication context. Fancy right?

It is possible to use multiple modules in a single component. If you want to compartmentalize your modules, this is the way to go. Just don’t forget to link them to your component, and add an instance of it in the builder.

Photo by Jacob Postuma on Unsplash

At this point, you might be a bit stiff now so why don’t you stretch first.

Now let’s get to where the action truly is.

@Inject annotation

The inject annotation instructs dagger that you need this dependency. Let’s take an activity for example. Activities are created and maintained by the OS so it is difficult to do constructor injection. Instead we will use field injection.

Note. For background regarding the code below, you may check this earlier tutorial of mine regarding MVP pattern.

Consider a component and module below:

This component provides a presenter for me. Notice that a function called inject is defined in FeatureComponent with a parameter MyActivity. Yup that’s right. This method is what we need to instruct dagger that it needs to provide our field dependencies right now.

For field injection, we need to make the field accessible, annotate it with @Inject and manually trigger injection.

During injection, dagger will look for your dependency, and create it. If your dependencies have other dependencies, dagger will create those dependencies first. Notice that instantiation is deferred until actual injection. This is one of the strongest suit of Dagger.

There is an important thing to note about @Inject and constructor injection. When you annotate a constructor with @Inject, dagger automatically adds it in the dependency graph. This means there is no need for you to create a @Provides method for it in the modules. Although I personally prefer creating @Provides methods as they are more intuitive and they are the way to go when annotation is not possible (such as 3rd party code).

@Singleton annotation

You guessed it right again. This annotation instructs dagger that it should only create one instance of it. Although in a wider sense, singleton refers to application scope. It means the scope and lifecycle of your object is tied to the application. Scoping is a complicated topic and maybe I will create a separate topic for this along with some advanced features.

There you have it. Another tool added to your arsenal.

Update: Part 2 is now available here.

--

--