Kotlin with Dagger 2 (Dependency Injection)

1
1020

I have to be honest with you and say that I didn’t have any plans to write about Kotlin with Dagger 2 in the Keddit app. In fact, I was about to write the last article with some conclusions about the Kotlin language, but I really like Dagger as a dependency injection framework, and nowadays it’s a hot topic as it’s being used heavily in many Android apps. So, let’s talk a little bit about Dagger 2 in Kotlin and the required steps to have it working in the app.

Kotlin with Dagger 2
Kotlin with Dagger 2

1Annotation Processing

Before we start, we should know that Kotlin has its own Annotation Processing Tool for Kotlin (kapt), and there is a great post from the JetBrains Team about this that I encourage you to read.

Kapt is disabled by default in Kotlin. This is intention because the way it works makes your build process a little slower. But, as with most of the issues related to Kotlin, this is something for sure they are going to solve soon.

In order to enable it you need to add this in the build.gradle file:

kapt {
    generateStubs = true
}

This will enable the compiler to generate stub classes required for interoperability between Java and Kotlin.

2Dagger 2

Dagger is a fully static, compile-time dependency injection framework for both Java and Android. It is an adaptation of an earlier version created by Square and now maintained by Google.

There are excellent tutorials about dagger. I really like above video from Jake Wharton.

Dependency

So let’s add Dagger 2 as dependency to our Keddit App in the build.gradle file:

compile 'com.google.dagger:dagger:2.4'
kapt 'com.google.dagger:dagger-compiler:2.4'
provided 'org.glassfish:javax.annotation:10.0-b28'

Please don’t forget to enable ‘generateStubs’ from this file as we saw before.

3Dagger API

As you know, Dagger has four main annotations to provide dependency injection. (There are others but are not covered here as we are not going to use it.)

  • @Modules + @Provides: provides dependencies.
  • @Injects: requests dependencies.
  • @Component: bridges between modules and injections.

Thanks to default constructors in Kotlin, we were already providing some dependencies from the constructor, so we don’t have to change so much our code in the Keddit App in order to provide these dependencies.

@Modules

I created three modules:

  • AppModule: provides the Context and the instance to KedditApp application.
  • NetworkModule: provides an instance of Retrofit.
  • NewsModule: provides the NewsAPI and RedditApi instances.

Also we need to provide the “NewsManager,” but it is not listed in any Module class. This is because you can annotate a constructor of a class that you created with the @Inject annotation, and Dagger by default will create a Factory and make this class available to be provided like any other @Provide in the module classes. Kotlin also allows you to add annotations inlined with the constructor in this way:

@Singleton
class NewsManager @Inject constructor(private val api: NewsAPI) {
    ...
}

@Injects

I’m requesting dependencies in two places:

  • NewsManager: as we saw previously in the constructor.
  • NewsFragment: we need here the NewsManager.
@Inject lateinit var newsManager: NewsManager

Remember that ‘lateinit’ allows you to define a non-nullable property and set the value later.

@Component

I created one component called “NewsComponent,” which will be the bridge between the modules and injections:

@Singleton
@Component(modules = arrayOf(
        AppModule::class, 
        NewsModule::class, 
        NetworkModule::class)
)
interface NewsComponent {

    fun inject(newsFragment: NewsFragment)

}

At least for now we don’t need to expose any other thing than a method to inject dependencies for the NewsFragment. Dagger will implement this method, search for injectable annotations and provide them.

Binding It All Together

As we know, Dagger will create a new class called DaggerNewsComponent, which will have a builder to create an implementation of our NewsComponent interface. We are going to create an instance of this and make it available from the KedditApp class in a static way:

companion object {
    lateinit var newsComponent: NewsComponent
}
newsComponent = DaggerNewsComponent.builder()
        .appModule(AppModule(this))
        //.newsModule(NewsModule()) NOT REQUIRED
        .build()

Modules with empty constructors are implicitly created by Dagger, so in this case we don’t need to do “.newsModule(…)”. The NewsModule will be created inside the builder for us.

We can use this newsComponent in this way from our NewsFragment:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    KedditApp.newsComponent.inject(this)
}

4Commit

And that’s all! We have everything set to use Dagger 2 to provide our dependencies.

5Conclusion

Kotlin is getting more and more exiting as time passes! Hope this article helps you to start using Dagger 2 into your own Kotlin projects. Please fell free to share your projects here and we can discuss more about this.

See you soon in another article! 🙂

 

Share your thoughts

Loading Facebook Comments ...
Loading Disqus Comments ...