Dependency Injection [Dagger2] for Android — Part 1

Anjula Sashika
JRC Tech Drive
Published in
6 min readOct 16, 2019

The dagger was introduced by the Square guys who are providing more awesome libraries like Retrofit, Picasso etc. Later based on the Dagger1, Google has developed the Dagger2 by improving the performance and adding more features like compile-time debugging. Now the daggger1 has been deprecated.

Dependency Injection

Dependency injection is a programming technique. Simply a class uses another class instance. Since this is a very popular technique in programming, you may also have used the dependency injection in your code without knowing that it is the dependency injection.

Image source: https://www.freecodecamp.org

According to the above image, class A has a reference to an object of class B. Then,

Class A DEPENDS ON Class B
Class B DEPENDENCY of Class A

Let’s take the below example.

class Phone {    var display: Display
var battery: Battery
constructor(){
display = Display()
battery = Battery()
}
fun makeACall(){
//Calling....
}
}

Inside the phone class constructor, the display and battery objects are getting created. So Display and Battery are the dependencies of the Phone class. Phone class is responsible for creating its display and battery objects. According to the above code when manufacturing a phone, the display and battery will get manufactured from zero for each phone. However, this is not happening in a real-life scenario.

Most of the time the display and battery also get manufactured somewhere else parallelly and get assembled when manufacturing the phone. When assembling the workers who are going to assemble the phone don’t need to consider how the display or battery is manufactured. Furthermore, different batteries with different capacities can be added to the same phone model. Even the display can be manufactured via a third party. It doesn’t matter.

Therefore, the same concept can be applied to the above class. We will be able to pass the display and battery instances instead of creating inside the Phone class. Then the phone class will not be responsible for creating the display and battery objects. Therefore, we will be able to pass different battery capacities to the phone object and manufacture different phones. In addition, the Display class and Battery class can be developed by another developer, the developer who is going to implement the Phone class doesn't need to know about the implementation of other classes.

constructor(display: Display, battery: Battery){
this.display = display
this.battery = battery
}

This is called the dependency injection.

As you can see, it’s not a must to use the dagger to do dependency injections. Then why Dagger?

Let’s consider a scenario like below.

class MainActivity : AppCompatActivity() {    override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var touchPanel = TouchPanel()
var backLight = BackLight()
var frontGlass = FrontGlass()
var wrappingPaper = WrappingPaper()
var shell = Shell()
var batteryCore = BatteryCore()
var display = Display(touchPanel, backLight, frontGlass)
var battery = Battery(wrappingPaper, shell, batteryCore)
var phone = Phone(display, battery) }
}

As you can see, to create a phone object we have to initialize several classes. Also, if we change a class constructor then we have to handle it everywhere in the project. That’s why we need the dagger to get rid of the above boilerplate codes. We will tell the dagger how to create objects on which sequence and it will help us to initialize the objects within two, three lines of code.

Image Source: https://www.freecodecamp.org

Setup Dagger2

Let’s go to the Github page of the dagger and follow their instructions.

//FILE - build.gradle(App)api 'com.google.dagger:dagger:2.24'
kapt 'com.google.dagger:dagger-compiler:2.24'

Now I’m gonna create classes for the above phone example. Also, I have added a log in each class to identify the initiation.

class Battery {
init {
Log.v("TAG_BATTERY","Battery Initialized")
}
}
--------------------------------------------------------------------class Display {
init {
Log.v("TAG_DISPLAY","Display Initialized")
}
}
--------------------------------------------------------------------class Phone constructor(display: Display, battery: Battery){ init {
Log.v("TAG_PHONE","Phone Initialized")
}

fun makeACall(){
Log.v("TAG_PHONE","Calling...")
}
}

And let’s make a call in MainActivity.

class MainActivity : AppCompatActivity() {

private lateinit var phone:Phone

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

phone.makeACall()

}
}

As you can see this won’t work since I haven’t initialized the phone variable. Let’s see how to do that using the Dagger.

Component

First of all, to use the dagger we need to know about the Component. The component is the most important part of the dagger. It is like the central nervous system. It is responsible for telling dagger how to generate all the above boilerplate codes and to provide the necessary instance for us.

Basically, a component is an interface annotated with @Component annotation. Let’s create a component for Phone class.

@Component
interface PhoneComponent {

fun getPhone():Phone

}

Here I have added a method without a method body. The name of the method doesn't matter, you can give any name for that. Apart from those we don’t have to do anything else in here. How to implement this method will be handled by the dagger.

Constructor Injection

As I said, the dagger will be able to create the necessary instances for us, but we have to tell the dagger which objects are needed for us. For that, we are going to use @Inject annotation.

In our Phone class, we are going to mention @Inject at the constructor. Then the dagger knows how to initiate the Phone object.

class Phone @Inject constructor(private var display: Display,private var battery: Battery) {
...

But as you can see to initiate the phone, we need a display and a battery. So, we have to tell the dagger how to initiate those classes by adding @Inject with the constructor of each class.

class Display @Inject constructor() {
init {
Log.v("TAG_DISPLAY","Display Initialized")
}
}
--------------------------------------------------------------------class Battery @Inject constructor(){
init {
Log.v("TAG_BATTERY","Battery Initialized")
}
}

Now the dagger knows how to create a phone.

This is called constructor injection. Remember! You can use the @Inject annotation on a single constructor only.

Okay! Let’s go to the MainActivity and get the phone from the phone component.

class MainActivity : AppCompatActivity() {

private lateinit var phone:Phone

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

var phoneComponent:PhoneComponent =
DaggerPhoneComponent.create()
phone = phoneComponent.getPhone()

phone.makeACall()

}
}

As you can see, we have created a phone component using a class called DaggerPhoneComponent. This class is generated by the dagger. If you can remember our PhoneComponent is an interface. The dagger has implemented all the necessary codes for the component and named it with a prefix “Dagger”. ( If the DaggerPhoneComponent still not available then please build the project and give a try. )

If you run the project now you will be able to see the logs as below.

If you want to see how the dagger has implemented the component, just check the DaggerPhoneComponent class.

public final class DaggerPhoneComponent implements PhoneComponent {
private DaggerPhoneComponent() {

}

public static Builder builder() {
return new Builder();
}

public static PhoneComponent create() {
return new Builder().build();
}

@Override
public Phone getPhone() {
return new Phone(new Display(), new Battery());}


public static final class Builder {
private Builder() {
}

public PhoneComponent build() {
return new DaggerPhoneComponent();
}
}
}

As you can see, the dagger has overridden and generated the getPhone() method body and returning an instance.

Did you know about the Directed Acyclic Graph (DAG)?
To know all these dependencies, the component creates a dependency graph.

Directed Acyclic Graph

Those arrows are pointed to one direction, therefore DIRECTED.
No cycles, that's mean ACYCLIC.
And GRAPH.
DAG, so this is how the name DAG+GER was inspired from.

Well, this is not all about the dagger. In my next article, I’m planning to discuss the Modules, Providers and field injections.

Thanks for reading!

--

--

Anjula Sashika
JRC Tech Drive

Great men are not born great, they grow great. (The Godfather)