In this post I will talk about Dependency Injection with some general examples, what is dependency, what is injection, what happens without it, what happens with it, why do you need it and how to use it on an Android project using Dagger 2.
What is Dependency?
To understand what Dependency Injection is and how it works we first need to understand what are dependencies.
In short, in object oriented programming a dependency is a coupling between two classes of our code, usually because one of them uses the other to do something.
Let’s take a simple example to understand this better:
We have two objects A and B. A needs B to do its job, therefore B is a dependency of an A.
Why Dependencies are bad?
To many dependencies will lead to hard dependency problems which will make our code:
- Hard to reuse
- Hard to test
- Hard to maintain (when project scales up)
Reusability is one of the core commandment of OOP. When classes and methods are coupled and dependant on many things, its reusable nature decreases.
In order to test if our method or class works properly, in most cases, we will need to mock some objects. But if there are so many dependencies within that method or the class it will be hard or impossible to test it.
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.
If our code can not be tested properly and the components are not reusable and at the same time the project continues to grow, at some point it will become very difficult to maintain.
Now that we now what dependencies are it’s much easier to explain what Dependency Injection (DI) is.
Dependency Injection is just one of the techniques to avoid dependencies. It is a technique where one object supplies the dependencies of another object. The general concept behind Dependency Injection is called Inversion of Control. According to this concept a class should not configure its dependencies statically but should be configured from the outside. In other words, no class should instantiate another class but should get the instance from a configuration class.
Dagger 2 is one of the open source DI frameworks which generates a lot of boilerplate code for us. It’s the second version of the popular Dagger framework developed by Square inc. Relations between classes in application are represented by Direct Acyclic Graph, hence the name.
Why Dagger 2?
Right now this is the only DI framework which generates fully traceable source code in Java which mimics the code that user may write by hands. It no longer uses reflection, which means it’s more traceable and easy to debug. Also, simplicity and performance of the generated code are on the same level as the hand written code. Long story short, Dagger 2 generates all the dependency injection boilerplate for you.
How dependencies are formed
How does it work?
Dagger 2 works on Annotation processor. So all the code generation is traceable at the compile time.
Annotation processors are code generators that eliminate the boilerplate code by creating code for you during the compile time.
Annotations are the class of metadata, that can be associated with class, methods, fields and even other annotations. Annotations in Java are used to provide additional information, so it is an alternative option for XML and Java marker interfaces. These methods can also be used during the runtime via reflection.
How to use it?
There are 4 main parts in Dagger 2:
- @Inject (base annotation wherby the dependency is requested)
- @Providers (classes which methods provide dependencies)
- @Module (methods inside @Module, which tell Dagger how we want to build and present a dependency)
- @Component (bridge between @Inject and @Module)
First and most important annotation. We can use it for:
- Consturctor injection
- Field injection
- Method injection
Basically , this annotation will tell the Dagger what dependencies need to be transferred to the dependant.
This annotation is used to create the interface which contains methods specifying where you want to perform the injection. In other words, component is a bridge between the generated code and the dependencies.
This annotation declares which objects you want to be available for injection.
For example. We can have a module called DairyModule and this module can provide Milk and Yogurt dependencies to other classes. In this case we need to mark the DairyModule with @Module.
This annotation is used in classes annotated with @Module and is used for methods which provides objects for dependencies injection.
In this article we covered some basic usages of Dagger 2. We already can see some of its strengths and weaknesses, but there is still a lot more to explore. Like @Scope, @Qualifer and how to manage the component. I am sure you have realized how Dagger 2 will change the way we develop our project, especially when combined with MPV pattern and RxJava when it will unleash its full potential.
For me, the best way to understand Dagger 2 is by reading its generated code, in most cases, if you get lost, it will help you to to figure out your problem. Also, I recommend to check the documentation.