Dagger 2 Starter Series
Part 0 - Dependency Injection Starter
Part 1 - Declaring Dependencies
Part 2 - Requesting Dependencies
Part 3 - Scoping
Dagger 2 is a dependency injection framework for Java. It is Google’s improved version of Dagger by Square. If you are not familiar with dependency injection, you need to take a look at this Dependency Injection Starter then continue with this article.
Why use Dagger?
Usually, classes have dependencies and these dependencies have dependencies as well. Like other DI frameworks, Dagger 2 organizes all your dependencies and the dependencies of your dependencies and links them together, forming a dependency graph, a dependency acyclic graph to be specific, or a DAG. This is hard to manage manually. You will end up having tons of boilerplate code. You have to think about how to provide object instances, how to resolve transitive dependencies, how to inject dependencies to anyone who needs them, how to manage object instances or scopes, etc.. Dagger simply lets you define dependencies for the DAG and helps you draw out dependencies from it without worrying about the complications of dependency injection itself hence the name DAGger.
Declaring Dependencies
Dagger doesn’t have superpowers to predict the future and supply dependencies that you have requested from it right off the bat. It has to know what objects to include in the graph and how to construct those objects. There are basically two ways to help Dagger with this:
1. By Defining Modules and Provider methods
You simply have to create a module - a plain Java class with an @Module
annotation. Inside it, you have to write methods annotated with @Provides
and return the types that you want to be added to the DAG.
If a type depends on some other type in order to be instantiated (in other words, it has a transitive dependency), you are allowed to declare provider method parameters to be able to construct and configure the object.
As mentioned earlier, Dagger is the one who will manage the satisfaction of all dependencies and their respective transitive dependencies for you. You only have to make sure that those transitive dependencies are going to be included in the DAG by creating provider methods that return the transitive dependencies’ types or by following step #2.
It is also best to group modules and provider methods in a logical manner since they are really designed to be like that. You can define modules to include other modules to maintain reusability and modularity.
If a provider method’s type relies on objects that cannot be supplied by other provider methods in its enclosing module or any included module, those objects can be supplied by exposing setter methods or constructor parameters, storing them as fields, and accessing them in provider methods. This is useful if you do not have control over the instantiation of certain objects such as those that are made by the system (like Android’s Context) or other third-party classes (like some of your favorite SDK’s objects).
2. By Annotating Class Constructors with @Inject
The second way to satisfy dependencies is by using the @Inject
annotation. It has another purpose, its main purpose actually, which you will learn about later. For now, you just have to know that when a class constructor is annotated with @Inject
, its type is automatically added to the DAG. There is therefore, no need to write a provider method in a module that returns the type.
To be continued
So far, you already know how to declare types to be included in the DAG generation. Our efforts will be useless if we are not going to use those! In the next part, we will learn about how to tell Dagger to get dependencies from the DAG a.k.a the injection part in dependency injection.