Using Dagger 2 in Android with Kotlin

What made me do this article?

I started programming Android applications few months ago. I went through fundamental and more advanced guides. None of them mentioned dependency injection. Without it I struggled to make proper unit tests. I decided that I have to make it work.

I looked around and found Dagger 2. The project developed by Google that provides dependency injection for Android applications. Sadly, I had a hard time making it work with Kotlin.

I have read many articles, but they had only scraps of necessary information. Combining them together I made it work. This post is a summary of my small research. It won’t be about Dagger 2 basics. If you want to know more, read official user’s guide. Those are articles that inspired me:

How to setup Dagger 2 with Kotlin?

First of all, add dependencies to app/build.gradle and enable kapt.

...

apply plugin: 'kotlin-kapt'

android {
    ...
}

dependencies {
    ...
    implementation 'com.google.dagger:dagger-android:2.x'
    implementation 'com.google.dagger:dagger-android-support:2.x'
    kapt 'com.google.dagger:dagger-android-processor:2.x'
    kapt 'com.google.dagger:dagger-compiler:2.x'
}

Provide modules to inject

Organize your code in modules that provide dependencies. Activities and fragments are dependencies too. They need to be in special abstract modules that use @ContributesAndroidInjector annotation on methods.

@Module
abstract class ActivityProvider {
    @ContributesAndroidInjector
    abstract fun mainActivity(): MainActivity
}

For other objects write modules with methods annotated with @Provides.

@Module
class CoffeeModule {
    @Provides
    @Singleton
    fun coffeeService() = CoffeeService()
}

class CoffeeService {
    fun prepareCoffee() = "Here! Espresso for you"
    fun fetchCoffee() = "espresso"
}

OrderService depends on CoffeeService. You don’t need to use @Inject annotation to do this with Dagger.

@Module
class OrderModule {
    @Provides
    @Singleton
    fun orderService(coffeeService: CoffeeService)
     = OrderService(coffeeService)
}

class OrderService(private val coffeeService: CoffeeService) {
    fun askForOrder() = "Would you like some ${coffeeService.fetchCoffee()}?"
}

Prepare your Application

Next add AppComponent that extends AndroidInjector<DaggerApplication>. It is vital that one of the included modules is AndroidSupportInjectionModule.

@Singleton
@Component(modules = [AndroidSupportInjectionModule::class, ActivityProvider::class, CoffeeModule::class, OrderModule::class])
interface AppComponent : AndroidInjector<DaggerApplication>

Add your own DaggerApplication implementation. This will be the starting point of your Android application.

class InjectionExampleApplication : DaggerApplication() {
    override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
        val appComponent = DaggerAppComponent.builder()
            .build()

        appComponent.inject(this)

        return appComponent
    }
}

Don’t forget to add attribute android:name in AndroidManifest.xml.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.github.wpanas.injectionexample">

    <application
        android:name=".InjectionExampleApplication"
        ...
    >
        ...
    </application>

</manifest>

From now on, dependencies registered by modules in AppComponent will be available for injection.

Inject dependencies

The last step is injecting those dependencies into your activities. Change parent class of your MainActivity from AppCompatActivity to DaggerAppCompatActivity. Then add your dependencies as lateinit var properties with @Inject annotation.

class MainActivity : DaggerAppCompatActivity() {

    @Inject
    lateinit var coffeeService: CoffeeService

    @Inject
    lateinit var orderService: OrderService

    ...
}

The same you can do with all activities and fragments. Add prefix Dagger- to theirs parents class names. This will ensure that dependencies are injected. Don’t forget to add those activities and fragments to module like in ActivityProvider.

Summary

Those simple steps enables you to make Dagger 2 work with Kotlin. All this code is captured in this repository. For more complex example you can also check out this project of mine.

comments powered by Disqus