This article will take about 2 minutes to read.
Kotlin is a wonderful language that lets us increase the safety of existing Java codebases. You may find yourself in a situation where you want to try it out, but are worried about the compatibility of frameworks you use. If you use Dagger2
for dependency injection, good news: Dagger in kotlin is mostly the same!
Injection works as normal, and is done via either a lateinit var
or a val
@Singleton
class NewsManager @Inject constructor(private val api: NewsApi) {}
// OR
@Inject lateinit var newsManager: NewsManager
this ensures that the variable cannot be changed later, but we have to ensure that we do not use it before it is initialized (kotlin does not have default values for uninitialized fields, so null checks won’t save you.)
We would inject this like normal in a startup method of an Activity
or Fragment
.
When defining a provider, don’t infer type, make it explicit instead, as inferring leads to subtle bugs. Dagger will not be able to infer which type should be injected!
/*✅*/ @Provides fun provideDiskCache(): DiskCache { return DiskCache() }
/*✅*/ @Provides fun provideDiskCache(): DiskCache = DiskCache()
/*✅*/ @Provides fun provideDiskCache(): Cache { return DiskCache() }
/*✅*/ @Provides fun provideDiskCache(): Cache = DiskCache()
/*❌*/ @Provides fun provideDiskCache() = DiskCache() // we may be expecting type Cache instead ¯\_(ツ)_/¯
Static providers must be moved into the companion object.
Notice that the @Module
annotation has to be duplicated onto the companion object, so it will apply.
@Module
abstract class DataModule {
@Binds abstract fun provideCache(diskCache: DiskCache): Cache
@Module
companion object {
@JvmStatic
@Provides
fun provideDiskCache(): DiskCache = DiskCache()
}
}
@Named
annotations will have to be prefixed with field
@Inject @field:Named("ioExecutor") lateinit var ioExecutor: Executor
The same goes for all injected properties
@Inject @field:ForApi lateinit var gson: Gson