· 4 min read
How to use Dagger 2 on Android with Kotlin (KAD 20)
Virtually everyone who wants to create code on Android in a decoupled and easy-to-test way, resorts to Dagger sooner or later.
Although there is something that works a bit differently when setting up Dagger in Kotlin, most of it is quite simple, and in a few steps I’m going to show you here today.
Also be aware that, thanks to the power of Kotlin, there are other ways to solve the injection, and even some libraries made exclusively in Kotlin for it.
But Dagger remains a perfectly valid option, and one of the most versatile (if not the most).
Disclaimer: In this article I won’t explain how Dagger 2 is used, this is already known. If you have any questions, I wrote some articles about dependency injection a while ago.
If all this passionate you as to me, I encourage you to sign up for my free training where I will tell you everything you need to learn about how to create your Android Apps in Kotlin from scratch.
Configuring the project to use Dagger 2
If you’ve already configured the Kotlin plugin in your project, all you need to do is configure kapt
.
If you already used Dagger, you probably know apt
. kapt
is just the version for Kotlin, which creates the necessary self-generated classes for Dagger.
To configure it, you need to add the following to build.gradle
:
kapt {
generateStubs = true
}
You can add it just before the dependencies section. If you want, you can instead use the new experimental plugin, which is pretty stable already:
apply plugin: 'kotlin-kapt'
Now you just need to add the dependencies of the Dagger compiler (using kapt
to not be included in the apk) and the actual library:
kapt 'com.google.dagger:dagger-compiler:2.5'
compile 'com.google.dagger:dagger:2.5'
Everything is ready to start using Dagger.
Main module implementation
As you may know, for the main graph you’ll need a Module
and a Component
.
The application module, in this simple example, will only return the instance of the application itself.
To do this we’ll create a class annotated with @Module
, which will receive the application instance via constructor, store it in a property, and return it using a method annotated with @Provides @Singleton
:
@Module
class AppModule(val app: App) {
@Provides
@Singleton
fun provideApp() = app
}
You can see that, even for this easy class, the code is much simpler than in Java.
Now we have to implement the Component
, which needs an array of modules to load, and specifies who is going to be able to manually inject it:
@Singleton
@Component(modules = arrayOf(AppModule::class))
interface AppComponent {
fun inject(app: App)
}
Just create the class App
, which will be responsible of generating the graph:
class App : Application() {
val component: AppComponent by lazy {
DaggerAppComponent
.builder()
.appModule(AppModule(this))
.build()
}
override fun onCreate() {
super.onCreate()
component.inject(this)
}
}
The interesting thing to see here is that, thanks to the lazy
statement, we can specify the value of the graph in the definition of the property, and thus get read-only access to that property.
The code defined by the property won’t be executed until component.inject (this)
is done, so that by that time this
already exists and can be created securely way.
One module implementation per scope
The modules by scope allow that part of the graph only to live during the lifetime of the object that creates it.
In this way, we can create subgraphs that live and die with an Activity, for example.
We would create our module with what we need:
@Module
class HomeModule(val activity: HomeActivity) {
}
A Subcomponent
in a very similar way to the previous one, indicating that it’ll be injected into the HomeActivity
:
@Singleton
@Subcomponent(modules = arrayOf(HomeModule::class))
interface HomeComponent {
fun inject(activity: HomeActivity)
}
And a plus
method in AppComponent
, to indicate that this component can be added subcomponents of that type:
interface AppComponent {
...
fun plus(homeModule: HomeModule): HomeComponent
}
Ahora, en la HomeActivity
tan solo necesitas declarar el subcomponente:
val component by lazy { app.component.plus(HomeModule(this)) }
Y puedes inyectarlo después del setContentView
:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
component.inject(this)
}
If you’re wondering where app
comes from, it’s a extension property that looks like this:
val Activity.app: App
get() = application as App
It’s simply a way to avoid having to do casting every time you access application
if you have your own custom one.
Conclusion
Dagger 2 is also easy to use in Kotlin. You no longer have an excuse to implement a great decoupled architecture in Kotlin.
If you like what you’ve seen, I encourage you to sign up for my free training, where I’ll tell you everything you need to learn about how to create your own Android Apps in Kotlin from scratch.