Hilt - How can I inject dependencies into adapter?

Viewed 2192

I am providing dependency in module:

@Provides
@Singleton
fun provideImageUtil(@ImageUrl imageUrl: String): ImageUtil = GlideImageUtil(imageUrl)

I am trying to inject it into RecyclerView adapter:

class MainAdapter(private val goods: ArrayList<GoodItem>) : RecyclerView.Adapter<MainAdapter.DataViewHolder>() {

    @Inject
    lateinit private var imageUtil: ImageUtil

I used to inject this way using Dagger:

object Injector {

    lateinit var appComponent: AppComponent

    fun initAppComponent(context: Context){

        if(context is Activity){
            throw IllegalStateException("pass an Application as an argument to avoid memory leaks")
        }

        appComponent = DaggerAppComponent.builder()
                .appModule(AppModule(context))
                .build()

    }

}

In adapter:

init {
    Injector.appComponent.inject(this)
}

How can I inject dependency into the adapter using Hilt? As I understood now "appComponent" is generated by Hilt. How can I access it?

2 Answers

First create EntryPoint in your custom class

@EntryPoint
@InstallIn(SingletonComponent::class)
interface MyEntryPoint {
    fun getImageUtil(): ImageUtil
}

It is simple interface with @EntryPoint annotation. Since your dependency (ImageUtil) is singleton you should use @InstallIn(SingletonComponent::class) annotation to declare component. Finally declare a method to get your dependency fun getImageUtil(): ImageUtil

You can get your dependency in init block of your Adapter

init {
    val myEntryPoint = EntryPointAccessors.fromApplication(context, MyEntryPoint::class.java)
    imageUtil = myEntryPoint.getImageUtil()
}

Full code

class MainAdapter(
    context: Context,
    private val goods: ArrayList<GoodItem>
) : RecyclerView.Adapter<MainAdapter.DataViewHolder>() {

    var imageUtil: ImageUtil

    @EntryPoint
    @InstallIn(SingletonComponent::class)
    interface MyEntryPoint {
        fun getImageUtil(): ImageUtil
    }

    init {
        val myEntryPoint = EntryPointAccessors.fromApplication(context, MyEntryPoint::class.java)
        imageUtil = myEntryPoint.getImageUtil()
    }
}

See also https://developer.android.com/training/dependency-injection/hilt-android#not-supported

You'll have to add an @AndroidEntryPoint and likely will have to inject the constructor,
because the imageUrl needs to come from somewhere; for example from Gradle:

javaCompileOptions {
  annotationProcessorOptions {
    arguments += ["imageUrl": "..."]
  }
}

And I think @Singleton @Provides / @Singleton @Binds annotations do require a scope.

Related