Dependency Injection with Dagger2

Photo by Andy Marches

IoC (Inversion of Control) is one of OOP’s (object oriented programming) principles, which allows us to write weakly bound code. The idea is that every system component should be as isolated as possible from other components. DI (Dependency Injection) is a specific form of this principle.

DI allows us to write code which is independent from the other parts of its system. That means we can use the same module of application logic in many places and we do not need to rewrite the module if we use it in a new place with a new part of the system.

Problems which we can avoid if we use dependency injection:
– Fragility and rigidity – changes in one part of an application lead to changes in other parts of its system;
– Immobility – to completely separate some part of the logic for repeated use.

A little confusing, isn’t it? Here’s an example of when we could use DI to improve our code: suppose we have an application which implements the MVP pattern. In this app we have MainActivity and according to the MVP pattern we have MainPresenter for this activity. To create the presenter we need two objects – UserModel and NewsModel. For creating these two models we need ApiService, PreferenceManager, OkHttpClient, Retrofit, DbManager, Context and others. Without DI it will look like this:

Looks terrible, yeah? To create the one MainPresenter object we need to create so many other objects. And now imagine that we need to change something in some model or manager. It’s look even worse.

Here’s what we get if we use DI:

Looks better, right? We just exclude object creation code from our activity to separate classes which Dagger has access to. We could exclude code to other classes without using Dagger, but what if we need the same objects in other presenters? Then we’d need duplicate code and that’s not good. With Dagger we put object creation code in one place and Dagger does all the magic for us.

What is Dagger 2? Why do we need to use it?

Dagger 2 is a library which allows us to implement DI in our project. This library is based on code generation unlike the other libraries, which work based on reflection. That means any errors show during the compilation stage. Dagger 2 also lets us remove our singletons and makes it easier to write tests for our application.

How does it work?

Dagger 2 works with the help of two key elements – ‘Modules’ and ‘Components’.

‘Modules’ are a simple class which contain logic for creating objects. Modules only contain methods which provide dependency. Generally, each Module includes objects which relate to some part of the application’s logic. For example, NetworkModule will contain the creation of OkHttpClient and ApiService or PresenterModule will contain methods to create all of the application’s presenters.

‘Components’ are connecting links between Modules and dependants. When we need some object we ask the Component. The Component knows which module can create the needed object and return it to the dependant.

Also, Components can use other modules to create a full hierarchy of objects. For example we have AppModule which provides context and PreferenceModule which enables our PreferenceManager to work with SharedPreferences. As you know, for SharedPreferences we need context. Dagger 2 independently finds context in AppModule and uses it in PreferenceModule. You just need to specify context as a parameter for the method which returns PreferenceManager inside PreferenceModule.

How to use Dagger 2

First we need to add Dagger 2 to our project:

Now we can use Dagger 2 in our project. Suppose we have PreferenceManager, looking something like this:

public class PreferenceManager {

}

As I explained above, we need two things to implement DI in our project using Dagger 2. These are a Module, which provides the object we need and a Component, which links our application component (like an activity or fragment) with our module.

First create the Module:

As you can see, we created two modules (ApplicationModule and PreferenceModule). It’s good practice to separate objects which are providers between modules, dividing them by logic (NetworkModule, DbModule, PresentersModule etc.). Class, which will be a Module, must be marked with the @Module annotation. These classes only have methods, which are ‘providing’ objects for us. If an object needs some other object to be created, we need to specify that object as a parameter for the method and not forget to create a providing method for it. Everything else, Dagger will do for us.

The next step is creating a component. There are two ways to create methods which return the needed objects: using get methods or inject methods.

The difference between get and inject methods:
If you use get methods, you need to write methods for every object which needs to be used and then you must use these get methods inside your activity.
If you use inject methods, you just need to write a method for every application component where you use objects (such as an activity, fragment etc.) and in activities only create needed objects with the @Inject annotation. Dagger 2 independently assign these variables using code generation.

Finally, the Application class:
If your module needs something like Context, you need to pass it to that module’s constructor and when you create the main Dagger Component (DaggerApplicationComponent) just add creation of this module (applicationModule(new ApplicationModule(this))).

You could notify that Android Studio light some code you wrote. That’s because Dagger 2 (unlike Dagger 1) work on code generation. So, you need just build your project. Click Build -> Make Project. When AS end building you will see that’s all okay. If build failed, you make some mistakes in code. It’s one more good thing in Dagger 2 – all error detect at compilation stage.

@Singleton

Also, if you need to create an object only once, you could use the @Singleton annotation to provide the method.

Then Dagger will create the object only once for use whenever needed instead of creating it again every time it’s needed.

Dependency graph

Together, the objects which a component can create are called a dependency graph.
The following code shows a dependency graph:

Example project: https://github.com/marinovskiy/Dagger2TestProject