In my application I use Hilt for dependency injection. I implemented a RetrofitModule
to provide dependencies for it in my Repository like this:
@Module
@InstallIn(ApplicationComponent::class)
object RetrofitModule {
@Singleton
@Provides
fun providesRetrofitClient(okHttpClient: OkHttpClient, baseUrl: String): Retrofit {
return Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build()
}
@Provides
fun providesBaseUrl(application: MyApplication): String {
return application.getBaseUrl()
}
@Singleton
@Provides
fun providesOkHttpClient(): OkHttpClient {
val okHttpClientBuilder = OkHttpClient.Builder()
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
okHttpClientBuilder.addInterceptor(loggingInterceptor)
return okHttpClientBuilder.build()
}
@Singleton
@Provides
fun providesService(retrofit: Retrofit): MyService {
return retrofit.create(MyService::class.java)
}
}
To provide a test base url for Mockwebserver configuration under test I implemented the functions inside the MyApplication
and MyApplicationTest
class
MyApplication.class
class MyApplication : Application() {
fun getBaseUrl() = "https://www.foo-production.com"
}
MyApplicationTest.class
class MyApplicationTest : Application() {
fun getBaseUrl() = "http://127.0.0.1:8080"
}
But when I build the app I'm getting this error:
A binding with matching key exists in component: de.xxx.xxx.MyApplication_HiltComponents.ApplicationC
...
I think the problem is this method
@Provides
fun providesBaseUrl(application: MyApplication): String {
return application.getBaseUrl()
}
and there is a problem by providing MyApplication class
Hilt is not able to provide your exact MyApplication
instance, it's only able to provide a generic Application
instance (see Component default bindings
from Hilt Components).
This should fix the issue:
@Provides
fun providesBaseUrl(application: Application): String {
return (application as MyApplication).getBaseUrl()
}
That being said, there's a much more elegant way to implement that.
src/main/your/package/
create one UrlModule.kt
@Module
@InstallIn(ApplicationComponent::class)
object UrlModule {
@Provides
fun providesBaseUrl(application: MyApplication): String {
return "https://www.foo-production.com"
}
}
src/test/your/package/
(or src/androidTest/your/package/
if it's for UI tests) create the other UrlModule.kt
@Module
@InstallIn(ApplicationComponent::class)
object UrlModule {
@Provides
fun providesBaseUrl(application: MyApplication): String {
return "http://127.0.0.1:8080"
}
}