Dagger For Noob Android Developer

PAUL MATHEW
6 min readNov 17, 2022

--

Quick Intro : For someone who is so lazy about writing down anything this article(My first ever) is a herculean task . And the people who reads this can think why a person starts with Dagger instead of other libraries or components. Answers are simple

  1. for referring to myself and for people who asks hey do you know dagger for android or can you help me with this dagger thing.
  2. To make a profile so that when someone asks me to share the web urls t know how deep are in Android Development.

NB:- It will be little lengthy . Because I want to explain the things that I used in the codes . There are times I really needed someone to do the explanations for the codes I used or Library I added, and that is the only reason why I’m adding these explanations . I hope it will be helpful for someone .

Actual Content

When it comes to android development Dagger, Rxjava, kotlin coroutines etc.. are becoming main and things and all the projects and company needs these skill set(even if you are a fresher) so coming to the content.

Dependency Injection (DI) (read these section if you needs to explain what it is or else you can skip.)

In simple term:- it is a property that gives you the items or things you needs for your job, like if you are cooking this property will give you oil, gas, veggies etc.. you don’t need to create it.

In Technical terms this is a feature that gives a class all the objects it needs to execute all the codes inside without creating those objects and leaving them unattended after using .

class Car(){

private val engine:Engine=Engine()

fun driveCar(){
engine.start()
}
}

The car class needs Engine Class to move or start that is Car class is dependent of Engine

Issues with this setup are

  1. We can’t test the class Car(); Because it is linked with class Engine() without Engine()
  2. If there is any changes needed in the future it can’t be done, because it is not extensible . Class engine is hard coded into the class Car
  3. Lifetime of objects or Reusability: here lifetime of engine object is directly depended to the life time of class Car(). And because of that we can’t use the object of engine class in any other class .

This can be avoided using converting the above code into

class Car(private val engine: Engine){
fun driveCar(){
engine.start()
}
}

Here what we are doing is we are passing the Engine class object from outside (from where we are calling the class Car()), And what we are doing is we are passing the object inside the constructor of the class Car() ie; injecting the engine object into the constructor. This is called Constructor Injection. This is how dependency injection works(on way) .

Dagger 2

It is one of the popular framework in DI

Properties of Dagger2

  1. Compile Time dependency Injection framework
  2. It is Annotation Based framework
  3. It will inject or add objects to the desired places
  4. It will manage the lifetime of the objects.

In Dagger2 there are mainly three things

  1. Consumer: class that uses the objects created by Dagger2. Like engine object in the top code. And it is annotated as @Inject
  2. Producer: class that produce the object or property to be consumed by the consumer(Modules). @Module, @Provides, @Binds
  3. Connecter: Connect the consumer with producer. Annotated using @Component

Example.
First let me add a non dagger code and from there I will tell you how to convert it into the Dagger method

package com.personal.daggerformedium

class UserRepo {

fun saveUser(name: String, email: String) {
println("User added")
}
}
package com.personal.daggerformedium

class EmailService {
fun send(to: String, body: String, from: String) {
println("Email Send")
}
}
package com.personal.daggerformedium

class UserInteraction(
private val userRepo: UserRepo,
private val emailService: EmailService
) {

fun registerUser(email: String, name: String) {
userRepo.saveUser(name, email)
emailService.send(email, "Msg Body", "from_emailId@gmail.com")

}
}
package com.personal.daggerformedium

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

val userInteraction = UserInteraction(UserRepo(),EmailService())
userInteraction.registerUser("new_email@id.com","Sample Name")
}
}

In the above codes there are 4 classes
1) UserRepo :- to add user data like mail and name

2) EmaiService :- to send email using with required input

3)UserInteraction :- to connect the above 2 classes or functionalities.

4)MainActivity :- to make use of theese functionalities.

In the UserInteraction class you can see that fun registerUser() and it is used to send email and add user into the system. and for this class to function properly it needs UserRepo() and EmailService() and we have passed the objects to the UserInteration() class in the construction it is called Constructor Injection and because of this type of implementation UserInteraction() class

  1. can be Unit tested
  2. Extensible
  3. Lifetime or reusability of the class .

Coming to the MainActivity class()

val userInteraction = UserInteraction(UserRepo(),EmailService())

in this line you can see how the object of UserIntraction() is created and how the requred classes passed into it. And it is called Manual Dependency Injection . The problem with this is if we want UserIntaction() in multiple places we need to create the objects of the other classes multiple times.

And we use Dagger to overcome the Manual DI. Now lets convert it into Dagger DI.

Implementation

By implementing Dagger we can ask Dagger for the objects of the item we needed, here we needs objects of UserRepo() and EmailService()

Inorder to add Dagger into the project we need to add the below codes into the gradle file of the module.

implementation 'com.google.dagger:Dagger:2.41'
kapt 'com.google.dagger:dagger-compiler:2.41'

and we need to add kapt plugin also in the top like this

plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
}

KAPT :- Kotlin Annotation Processing Tool, Dagger is working with Annotation so we need to add this

We ask dagger for the objects and dagger will provide it . That is how it works, And in-order to provide objects whenever we ask dagger needs to know which are all module and where are we calling them

Now create an Interface class like this

import dagger.Component


@Component
interface UserInteractionComponent {

fun getUserInteraction():UserInteraction
}

and after this we need to change the UserIneraction() class

first we need to add @Inject to the class ; reason is we are passing UserInteraction class object into the Component class. Code below

import javax.inject.Inject

class UserInteraction @Inject constructor(
private val userRepo: UserRepo,
private val emailService: EmailService
) {

fun registerUser(email: String, name: String) {
userRepo.saveUser(name, email)
emailService.send(email, "Msg Body", "from_emailId@gmail.com")

}
}

By @inject we are telling dagger that it needs to pass the object to the component class. Here we are passing class object.

Now we need to tell Dagger that UserInteraction() class needs UserRepo() and EmailService() objects so we need to inject them to the UserInteraction() class

Modified Classes

import javax.inject.Inject

class UserRepo @Inject constructor() {

fun saveUser(name: String, email: String) {
println("User added")
}
}
import javax.inject.Inject

class EmailService @Inject constructor() {
fun send(to: String, body: String, from: String) {
println("Email Send")
}
}

So whenever UserIntraction class object needed Dagger will call it’s constructor() and it contain UserRepo() and EmailService() and whenever those object needed it wil call the respective constructor.

After all these modifications to the code we need to build the code. Because Dagger is a compile time framework.

Let’s access the component calss in MainActivity and remove those old codes.

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

val userInteraction = DaggerUserInteractionComponent.builder().build().getUserInteraction()
userInteraction.registerUser("new_email@id.com","Sample Name")
}
}

In this line “ val userInteraction = DaggerUserInteractionComponent.builder().build().getUserInteraction()”

DaggerUserInteractionComponent is the automatic class that will be created after successful build and from the Class name you can see that after Dagger it is the Component interface class that we created.

So whenever we want to use registerUser() we can use

val userInteraction = DaggerUserInteractionComponent.builder().build().getUserInteraction()
userInteraction.registerUser("new_email@id.com","Sample Name")

these two line and we don’t need to create any objects or anything.
Dagger will handle that for us.

If we want any global functions or objects we can add them inside the component interface class and dagger will do the rest. Like the below code.

One thing to note here is dagger knows about the @inject inside the UserRepo() class so there won’t be any error.

@Component
interface UserInteractionComponent {

fun getUserInteraction():UserInteraction
fun addUser():UserRepo
}

By doing these Simple implementation of Dagger is Done.

--

--

PAUL MATHEW

A Noob android developer who try to make some notes which obtained by going through different tutorials and stackoverflow.