Dagger-Android-Part 4

Dheeraj Andra
MindOrks
Published in
3 min readApr 27, 2019

I hope that the prerequisites to understand Dagger covered in parts 1, 2 and 3 are understood.

If you haven’t visited them, I request you to go through these parts before continuing with this part of the series.

In this part of the series, we are going to start with the actual implementation of Dagger with a project.

We will be referring to this project for understanding Dagger

This has everything implemented wrt Dagger. So, let’s understand it step by step, the way we learned the concepts in Part 1, Part 2 and Part 3.

Firstly before we proceed, let’s add the dependencies to the application level build.gradle file

// Dagger
implementation "com.google.dagger:dagger:$dagger_version"
kapt "com.google.dagger:dagger-compiler:$dagger_version"

Define the dagger_version in the project level build.gradle file:

ext {
dagger_version = '2.21'
}

Here, we are using kapt because we require annotations to be used in Dagger. Since kapt stands for Kotlin Annotation Processing Tool, we have to add the plugin in the application level build.gradle file :

apply plugin: 'kotlin-kapt'

Now, we have added the dependencies.

So, let’ s recall what wehavelearntin Part 1, Part 2 and Part 3. Firstly, we understood the basics of DI, how annotation processing is done and what it means, Qualifier and Scope, and then the Module, Provides, Inject and Component annotations.

Let’s implement our project also in a similar way. Firstly, let’s define scope and Qualifiers in our project:

@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class ActivityScope

And now, the Qualifiers:

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class MarutiCar

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class ToyotaCar

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class CarName

The Role of Scope and Qualifiers is explained in Part 2 of the series. But in brief, let’s see what these marutiCar and ToyotaCar Qualifiers do. Both cars are of type Car and since to differentiate their respective properties in the application , we have used Qualifiers.

Now, let’s define our Model class, which is Car.

class Car @Inject constructor(
@CarName val name: String
) {
fun displayName() {
//Displays the name of the car
}
}

Now, we have a model class. Let’s define our Modules now. Remember, Module annotation is used on a class that contributes to the dependency/Dagger graph, meaning, it contains methods that provides the dependencies.

Firstly, let’s create ActivityModule:

@Module
class ActivityModule(var activity: AppCompatActivity) {
@Provides
fun provideActivity(): Activity = activity
}

Application Module :

@Module
class ApplicationModule(val application: MyApplication) {

@Provides
@Singleton
fun provideApplication() : Application = application

@Provides
@Singleton
fun provideContext() : Context = application

}

MarutiCarModule :

@Module
class MarutiCarModule {
@Provides
@CarName
fun provideName(): String = "Maruti Swift Dzire"

@Provides
@Singleton
@MarutiCar
fun provideCar(car:Car) = car
}

ToyotaCarModule:

@Module
class ToyotaCarModule {
@Provides
@CarName
fun provideName() : String = "Toyota Innova"

@Provides
@ActivityScope
@ToyotaCar
fun provideCar(car: Car) = car
}

Now let’s define our Components. So components are basically the interfaces that connects the Dependency Providers (Module classes) and Dependency consumers.

Let’s define ApplicationComponent first:

@Singleton
@Component(
modules = [
ApplicationModule::class,
MarutiCarModule::class
]
)
interface ApplicationComponent {

fun inject (application: MyApplication)

@MarutiCar
fun getCar() : Car
}

We should define the module classes that are used in this ApplicationComponent. We are providing the scope for Application Component as @Singleton because we need the values throughout the application

Now, let’s define ActivityComponent:

@ActivityScope
@Component(
dependencies = [ApplicationComponent::class],
modules = [ActivityModule::class,
ToyotaCarModule::class]
)
interface ActivityComponent {

fun inject(activity: MainActivity)

@ToyotaCar
fun getCar() : Car
}

Here, in activity component we are using dependencies = [ApplicationComponent::class], because, though this is a simple example, we might be providing singleton instances in the Application Module class which might be required in Activity Modules (like networkProvider etc.,). When these values are required by Activity Modules, they take them from the available Dagger/Dependency graph instead of creating new ones.

So, we have defined our Qualifiers, Scopes, Modules, Provides methods and Components. So we have everything ready at compile time. Now, let’s use them by using the @Inject in our final part, Part 5

Congratulations on applying the knowledge we have learnt from Part 1, 2 and 3 in this part.

That’s it for Part 4 of this series.

Thank you for your time!

Let’s connect on Twitter and LinkedIn

--

--