Hilt Android — Step by Step : Part2

Gözde Kaval
2 min readAug 19, 2020

--

On first story, we started with very basic implementation of Hilt, check here.

In this article, we will move forward one step: provide interface and how to inject them. Let’s create an interface with a basic implementation.

Providing Interfaces:

interface LoggerCallback {
fun log()
}
//Implementationclass LoggerImpl1 @Inject constructor() : LoggerCallback {

override fun log() {
Log.d("abc", "LoggerImpl1")
}
}
  • There is a problem, how can we provide an interface? Here we will use @Binds that provided specifically for interfaces.
@Provides
fun provideLoggerImpl1(): LoggerCallback ??
  • Lets add @Binds in our module:
@InstallIn(ActivityComponent::class)
@Module
abstract class LoggerModule {

@Provides
fun provideLogger3(@ActivityContext context: Context): Logger3 = Logger3(context)

@Binds
abstract fun provideLoggerImpl1(): LoggerCallback
}

error: A @Module may not contain both non-static and abstract binding methods

  • We cannot use @Binds and @Provides inside same module. Create another one for @Binds. Both module and bind method should be abstract.
@InstallIn(ActivityComponent::class)
@Module
abstract class LoggerBindsModule {

@Binds
abstract fun bindLoggerImpl1(loggerImpl1: LoggerImpl1): LoggerCallback

}
  • Inject in Activity and done!
@Inject
lateinit var loggerCallback: LoggerCallback

Different Implementation for Interfaces:

  • Now, we will create second implementation for LoggerCallback and pass activity as parameter. Then @Binds inside our binding module.
class LoggerImpl2 @Inject constructor(private val activity: FragmentActivity) : LoggerCallback {

override fun log() {
Log.d("abc", "LoggerImpl2 : ${activity.localClassName}")
}
}
//LoggerBindsModule@Binds
abstract fun bindLoggerImpl2(locationChecker: LoggerImpl2): LoggerCallback
  • Run and try:

error: [Dagger/DuplicateBindings] com.example.vacation.hilt.LoggerCallback is bound multiple times:
public abstract static class ApplicationC implements VacationApplication_GeneratedInjector,
^
@org.jetbrains.annotations.NotNull @Provides com.example.vacation.hilt.LoggerCallback com.example.vacation.hilt.LoggerModule.provideLoggerImpl1()
@org.jetbrains.annotations.NotNull @Provides com.example.vacation.hilt.LoggerCallback com.example.vacation.hilt.LoggerModule.provideLoggerImpl2()

  • Ups, we provide same instance two times and they need to be identified. Here we will use Qualifiers:
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class First

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class Second
  • Now we need use them for our binds
@Binds
@First
abstract fun bindLoggerImpl1(loggerImpl1: LoggerImpl1): LoggerCallback

@Binds
@Second
abstract fun bindLoggerImpl2(locationChecker: LoggerImpl2): LoggerCallback
  • Run..

error: [Dagger/MissingBinding] com.example.vacation.hilt.LoggerCallback cannot be provided without an @Provides-annotated method.

  • We forgot to tell which logger we want inside activity:
@Inject
@First
lateinit var loggerCallback: LoggerCallback
  • Done.

Conclusion:

  • We learned how to provide interfaces with @Binds annotation and how to differentiate them with @Qualifier.
  • We will continue with different lifecycle scopes on next article.

--

--