Keddit — Part 10: Kotlin & Dagger 2 (Dependency Injection)

Juan Ignacio Saravia
AndroidPub
Published in
4 min readJul 22, 2016

--

Content

Part 10: Kotlin & Dagger 2

I have to be honest with you and say that I didn’t have any plans to write about 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.

Annotation Processing

Before to 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 which I encourage you to read.

After 1.1.x Kotlin version, you have to configure kapt in a different way in your gradle.build:

apply plugin: ‘com.android.application’
apply plugin: ‘kotlin-android’
apply plugin: ‘kotlin-android-extensions’
apply plugin: ‘kotlin-kapt’ // <- add this plugin

Commit

https://github.com/juanchosaravia/KedditBySteps/commit/cb4725b6eda4dac0e724b7445b9c15912fe9e0d8

Dagger 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 this 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.

build.gradle file updated:

https://github.com/juanchosaravia/KedditBySteps/blob/master/app/build.gradle

Dagger API

As you know, Dagger has 4 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: request dependencies.
  • @Component: bridge 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 3 modules:

  • AppModule: provide 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 2 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 provides them.

Binding Altogether

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 a 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 constructor 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)
}

Commit

And that’s all! We have everything set to use Dagger 2 to provide our dependencies. As you will see the commit has more new classes (Modules and Component) than code changed:

https://github.com/juanchosaravia/KedditBySteps/commit/296a7bcf4d416568590478186994f6f7417162d7

Conclusion

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! :)

Twitter: https://twitter.com/juanchosaravia

Next Article

Part 11: Continuous Integration with Kotlin (BuddyBuild)

--

--