Dagger 2 for Android, Part V ー @Inject for Constructor Injection

Tan Jun Rong avatar
Tan Jun Rong

In previous article, we went through @Inject annotation. It is typically used to inject dependency into a class. We then need to have a corresponding @Provides to provide the dependency to be injected.

However there is another usage for @Inject, that is to make it act as @Provides. When used in this way, @Provides can be omitted.

This article will discuss about how to use this.

Photo by It's me, Marrie from Pexels
Photo by It's me, Marrie from Pexels

The code example used in this article will be written in Kotlin for Android development.

Pre-requiresite: Understanding basic usage of Dagger 2: @Inject, Provides, @Module, and @Component. Read Part I, II above if you haven't 😀 👆

Without Constructor Injection

Before jumping into using constructor injection, let's consider how we can do it without constructor injection. Also, we will look at how to use Scope here.

After that, we will re-implement the same thing with constructor injection.

Let's begin!

Let's say we have a model class Taco 🌮:

Taco.kt
class Taco constructor() { val name: String = "Chicken Taco" }

And we want to inject it into an activity:

ConstructorInjectionActivity.kt
class ConstructorInjectionActivity : AppCompatActivity() { @Inject lateinit var taco1: Taco override fun onCreate(savedInstanceState: Bundle?) { ... } }

We would have to prepare a Module to provide the dependency:

TacoModule.kt
@Module class TacoModule { @Provides fun provideTaco(): Taco = Taco() }

Then, we will have to add the module to the component:

AppComponent.kt
@Component(modules = [TacoModule::class]) interface AppComponent { fun inject(activity: ConstructorInjectionActivity) }

And finally injecting it in the activity itself:

ConstructorInjectionActivity.kt
class ConstructorInjectionActivity : AppCompatActivity() { @Inject lateinit var taco1: Taco override fun onCreate(savedInstanceState: Bundle?) { + DaggerAppComponent.builder().build().inject(this) } }

With @Singleton scope, with @Provides

If we need to add Scope, we can add it along with @Provides:

TacoModule.kt
@Module class TacoModule { @Provides + @Singleton fun provideTaco(): Taco = Taco() }

And add it to the AppCompoennt:

AppComponent.kt
@Component(modules = [TacoModule::class]) @Singleton interface AppComponent { fun inject(activity: ConstructorInjectionActivity) }

By adding this scope will be implemented, so whenever we request for the dependency within the same scope, Dagger will provide the same instance of dependency.

How To Use Constructor Injection

Now, let's re-implement this with constructor injection.

We need to make a small change in Taco class, adding @Inject before the constructor keyword:

Taco.kt
-class Taco constructor() { +class Taco @Inject constructor() { val name: String = "Chicken Taco" }

Then we can remove the TacoModule.kt class entirely:

terminal
(taco project)$ rm TacoModule.kt

Also, remove it from the AppComponent:

AppComponent.kt
[email protected](modules = [TacoModule::class]) [email protected] interface AppComponent { fun inject(activity: ConstructorInjectionActivity) }

Now it will work as before when we inject it into an activity! 👇

ConstructorInjectionActivity.kt
class ConstructorInjectionActivity : AppCompatActivity() { @Inject lateinit var taco1: Taco override fun onCreate(savedInstanceState: Bundle?) { DaggerAppComponent.builder().build().inject(this) // use taco1 here } }

With @Singleton scope, with Constructor Inspection

Now let's implement the scope with constructor injection:

First add it to the AppComponent:

AppComponent.kt
@Component + @Singleton interface AppComponent { fun inject(activity: ConstructorInjectionActivity) }

Then add the scope to the Taco class along with @Inject:

Taco.kt
+ @Singleton class Taco @Inject constructor() { val name: String = "Chicken Taco" }

This way it will be able to achieve the similar scoping effect as before!

Summary

For simple cases, constructor injection allows us to quickly inject a simple class without having to write the @Module to provide the dependency.

Hope you find this post useful!

👋