This article contains a lot of information. So for the purpose of readability I have broken it into two parts.
Part 1: Deals with the introduction to the concept and overview of Dagger2.
Part 2: Contains Dagger2 implementation through an example.
To understand the Dagger2 usage in Android, let’s first try to understand the need for it. The important question is:
Why do we need Dependency Injection?
Dependency Injection in build upon the concept of Inversion of Control. Which says that a class should get its dependencies from outside. In simple words, no class should instantiate another class but should get the instances from a configuration class.
If a java class creates an instance of another class via the
new operator, then it cannot be used and tested independently from that class and is called a hard dependency.
So, what are the benefits of providing the dependencies from outside the class?
The most important advantage is that it increases the possibility of reusing the class and to be able to test them independent of other classes.
This sounds awesome to create a class that is not a specific implementation of a business logic.
Now that we understand a bit, we can go forward with dependency injection exploration.
The big question now is that, how do we do DI (Dependency Injection)?
To answer this question, we have to look back into the past.
A framework class called dependency container was used to analyzes the dependencies of a class. With this analysis, it was able to create an instance of the class and inject the objects into the defined dependencies via Java Reflections. This eliminated the hard dependencies. That way the class could be tested in isolation, ex. by using mock objects. This was Dagger1.
Main disadvantages of this process were two folds. First, the Reflection is slow in itself and second, it used to perform dependency resolution at runtime, leading to unexpected crashes.
This lead to the birth of Dagger2 forked from Square Dagger1 by Google.
The big changes that were brought in Dagger2 were generating the dependency graph using annotation processor. The classes providing the dependencies were now generated at build time using javax inject package. This facilitated the possible error checking before the application runs. The generated code is highly readable as if written by hand.
Note: Annotation Processor is a way to read the compiled files during build time to generate source code files to be used in the project.
If the above paragraph overwhelmed you then hang on till we start a real Android example.
For information purposes, I would like to mention some facts on DI.
The standard java annotations for describing the dependencies of a class are defined in the Java Specification Request 330 (JSR 330)
Mode of Injection:
- Constructor Injection: Injecting the method parameters.
- Field Injection: Injecting the member variable (must not be private).
- Method Injection: Injecting the method parameter.
Order of dependency injection according to JSR330
- The order in which the methods or fields annotated with
@Injectare called is not defined by JSR330. You cannot assume that the methods or fields are called in the order of their declaration in the class.
- As fields and method parameters are injected after the constructor is called, you cannot use injected member variables in the constructor.
Now that we have sufficient background and justifications, we can proceed to understand Dagger2.
I tend to visualize the dependency injection process with Dagger2 as follows:
A dependency consumer asks for the dependency(Object) from a dependency provider through a connector.
- Dependency provider: Classes annotated with
@Moduleare responsible for providing objects which can be injected. Such classes define methods annotated with
@Provides. The returned objects from these methods are available for dependency injection.
- Dependency consumer: The
@Injectannotation is used to define a dependency.
- Connecting consumer and producer: A
@Componentannotated interface defines the connection between the provider of objects (modules) and the objects which express a dependency. The class for this connection is generated by the Dagger.
Limitations of Dagger2:
- Dagger2 does not inject fields automatically.
- It cannot inject private fields.
- If you want to use field injection you have to define a method in your
@Componentannotated interface which takes the instance of the class into which you want to inject the member variable.
Now let’s move to the Part 2 of this article and experience Dagger2 in action. For Part 2 please follow this link.
Learning is a journey, let’s learn together!