Search code examples
androidkotlindagger-2android-jetpackdagger-hilt

How to generate objects with the same type in Hilt?


@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Singleton
    @Provides
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl("http://example.com/")
            .client(okHttpClient)
            .build()
    }

    @Singleton
    @Provides
    fun provideMyRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl("http:/my.com/")
            .client(okHttpClient)
            .build()
    }
}

Their difference is only baseUrl.


I tried to solve this problem by use @Qualifier.

interface RetrofitQualifier {
    @Qualifier
    @Retention(AnnotationRetention.BINARY)
    annotation class Retrofit

    @Qualifier
    @Retention(AnnotationRetention.BINARY)
    annotation class MyRetrofit
}
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

    @Singleton
    @Provides
    @RetrofitQualifier.Retrofit
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl("http://example.com/")
            .client(okHttpClient)
            .build()
    }

    @Singleton
    @Provides
    @RetrofitQualifier.MyRetrofit
    fun provideMyRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl("http:/my.com/")
            .client(okHttpClient)
            .build()
    }
}

And I use it by use @RetrofitQualifier.MyRetrofit in my class:

class MyRepository @Inject constructor(
    application: Application
)  {

    ...    

    @Inject
    @RetrofitQualifier.MyRetrofit
    lateinit var  retrofit:Retrofit


    private val service: Service = retrofit.create(Service::class.java)

    ...

    }

However, I was failed, the log is

kotlin.UninitializedPropertyAccessException: lateinit property retrofit has not been initialized

What should I do? Maybe use @Named? I am not sure...


Solution

  • Example with Qualifier, you can add this in the same file where you have your providers or even create a RetrofitQualifier.kt file and add them there.

    @Qualifier
    @Retention(AnnotationRetention.BINARY)
    annotation class RetrofitOne
    
    @Qualifier
    @Retention(AnnotationRetention.BINARY)
    annotation class RetrofitTwo
    

    And the @Provides

    @Singleton
    @Provides
    @RetrofitOne
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl("http://example.com/")
            .client(okHttpClient)
            .build()
    }
    
    @Singleton
    @Provides
    @RetrofitTwo
    fun provideMyRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl("http:/my.com/")
            .client(okHttpClient)
            .build()
    }
    

    Then in your Repository you can inject using two options

    Field injection

    // At field injection.
    @AndroidEntryPoint
    class MyRepository @Inject constructor(...) {
    
      @RetrofitOne
      @Inject lateinit var retrofit: Retrofit
    }
    

    As a dependency injected-constructor class

    // As a dependency of a constructor-injected class.
    class MyRepository @Inject constructor(
      @RetrofitTwo private val retrofit: Retrofit
    ) : ...
    
    

    But the thing is that perhaps you installedIn in another module where your Repository doesn't have visibility.

    About the @Named you can still use it but as per the documentation is recommended to use Qualifier