On this new series I will explain what dependency injection is, what its main purpose is and how to use it on an Android project by using Dagger, the best know implementation designed with Android in mind.
It will be a follow-up from my previous post about MVP for Android, because I know some of you are quite interested in see them implemented in the same project, and I think they work quite well together.
This first part is going to be only a little theory to settle the basis. It's important to understand what it is and why it exists, because if not we will think the benefits are not enough for the effort.
If we want to inject dependencies, we first need to know what a dependency is. In short, a dependency is a coupling between two modules of our code (in oriented object languages, two classes), usually because one of them uses the other to do something.
How do we test 'doSomething' without testing 'doSomethingElse'? If test fails, what method is the one that is failing? We can't know. And things get worse if this 'doSomethingElse' method saves something in database or performs an API call.
Every 'new' we write is a hard dependency we probably need to avoid. And no, writing less modules isn't a solution, don't forget single responsibility principle.
If we can't instantiate modules inside another module, we need to provide those modules in another way. Can you imagine how? Exactly, via constructor. That is basically what dependency inversion principle means. You shouldn't rely on concrete module objects, only on abstractions.
You already know! It consists of passing dependencies (inject them) via constructor in order to extract the task of creating modules out from other modules. Objects are instantiated somewhere else and passed as constructor attributes when creating the current object.
But here it comes a new problem. If we can't create modules inside modules, there must be a place where those modules are instantiated. Besides, if we need to create modules with huge constructors including lots of dependencies, code will become dirty and hard to read, with objects travelling around the inmensity of our app. That's what a dependency injector solves.
We can consider it as another module in our app that is in charge of providing instances of the rest of modules and inject their dependencies. That is basically its duty. The creation of modules is localized in a single point in our app, and we have full control over it.
Dagger is a dependency injector designed for low-end devices. Most dependency injectors rely on reflection to create and inject dependencies. Reflection is awesome, but is very time consuming on low-end devices, and specially on old android versions. Dagger, however, uses a pre-compiler that creates all the classes it needs to work. That way, no reflection is needed. Dagger is less powerful than other dependency injectors, but it's the most efficient.
Of course not! It makes easier to reuse your modules in other apps, or even change them in the same app. Think for example in an app which takes its data from some local files on debug and from an API service on release. That's perfectly possible by injecting one module or another on each case.
I know this post it's a bit hard, but I think it's very important to establish the terms we are going to deal with on next episodes. We already know what dependencies are, what we improve with dependency inversion and how we can implement it by using a dependency injector.
On next episode we will get our hands dirty. so stay tuned!