Reputation: 541
I want to use two different backend in my android application with different response format, i am using hilt as dependency injection with retrofit for network calling, which is great to work on.
as i have added my 2nd server network files and in app module, its giving me error which is listed at the end.
i need to know a way out in this situation without making any prominent architecture changes.
@Keep
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Singleton
@Provides
fun provideRetrofit(gson: Gson,@ApplicationContext appContext: Context): Retrofit = Retrofit.Builder()
.client(
OkHttpClient().newBuilder()
.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)).readTimeout(80,TimeUnit.SECONDS)
.addInterceptor(
ChuckerInterceptor.Builder(appContext)
.collector(ChuckerCollector(appContext))
.maxContentLength(250000L)
.redactHeaders(emptySet())
.alwaysReadResponseBody(false)
.build()
)
.build()
)
.baseUrl(UtilSingleton.instance!!.GetBaseUrl())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
@Provides
fun provideGson(): Gson = GsonBuilder().create()
@Provides
fun providePostsService(retrofit: Retrofit): ApiService =
retrofit.create(ApiService::class.java)
@Singleton
@Provides
fun provideApiRemoteDataSource(apiService: ApiService) = ApiRemoteDataSource(apiService)
@Singleton
@Provides
fun provideRepository(
remoteDataSource: ApiRemoteDataSource
) =
MainRepo(remoteDataSource)
/**----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------**/
@Singleton
@Provides
fun provideRetrofitEmall(gson: Gson,@ApplicationContext appContext: Context): Retrofit = Retrofit.Builder()
.client(
OkHttpClient().newBuilder()
.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)).readTimeout(80,TimeUnit.SECONDS)
.addInterceptor(
ChuckerInterceptor.Builder(appContext)
.collector(ChuckerCollector(appContext))
.maxContentLength(250000L)
.redactHeaders(emptySet())
.alwaysReadResponseBody(false)
.build()
)
.build()
)
.baseUrl(UtilSingleton.instance!!.GetBaseUrl())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
@Provides
fun providePostsServiceEmall(retrofit: Retrofit): EmallApiService =
retrofit.create(EmallApiService::class.java)
@Singleton
@Provides
fun provideApiRemoteDataSource(apiService: EmallApiService) = EmallApiRemoteDataSource(apiService)
@Singleton
@Provides
fun provideRepository(
remoteDataSource: EmallApiRemoteDataSource
) =
EmallRepo(remoteDataSource)
}
Build Error ->
Execution failed for task ':app:kaptLocalDebugKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptExecution
> java.lang.reflect.InvocationTargetException (no error message)
Full Log ->
D:\vaultsNew\vaultspaynewapis\app\build\tmp\kapt3\stubs\localDebug\com\uae\myvaultspay\di\AppModule.java:40: error: Cannot have more than one binding method with the same name in a single module
public final com.uae.myvaultspay.data.remote.ApiRemoteDataSource provideApiRemoteDataSource(@org.jetbrains.annotations.NotNull()
^D:\vaultsNew\vaultspaynewapis\app\build\tmp\kapt3\stubs\localDebug\com\uae\myvaultspay\di\AppModule.java:78: error: Cannot have more than one binding method with the same name in a single module
public final com.uae.myvaultspay.data.remote.emallremote.EmallApiRemoteDataSource provideApiRemoteDataSource(@org.jetbrains.annotations.NotNull()
^D:\vaultsNew\vaultspaynewapis\app\build\tmp\kapt3\stubs\localDebug\com\uae\myvaultspay\di\AppModule.java:48: error: Cannot have more than one binding method with the same name in a single module
public final com.uae.myvaultspay.data.repository.MainRepo provideRepository(@org.jetbrains.annotations.NotNull()
^D:\vaultsNew\vaultspaynewapis\app\build\tmp\kapt3\stubs\localDebug\com\uae\myvaultspay\di\AppModule.java:86: error: Cannot have more than one binding method with the same name in a single module
public final com.uae.myvaultspay.data.repository.EmallRepo provideRepository(@org.jetbrains.annotations.NotNull()
^warning:
File for type 'com.uae.myvaultspay.MyApplication_HiltComponents' created
in the last round will not be subject to annotation processing.
Execution failed for task ':app:kaptLocalDebugKotlin'.
> A failure occurred while executing
org.jetbrains.kotlin.gradle.internal.KaptExecution
> java.lang.reflect.InvocationTargetException (no error message)
Upvotes: 22
Views: 13127
Reputation: 2880
Kotlin Language
You can achieve by using Qualifier
. Let's see an example:
Create a kotlin class e.g. Qualifiers.kt and defined Qualifier
you need
import javax.inject.Qualifier
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class Auth
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class Setting
Your module class e.g. NetworkModule.kt
@Provides
@Singleton
@Auth //This will differentiate retrofit object
fun retrofitAuth(
client: OkHttpClient,
gsonConverterFactory: GsonConverterFactory
): Retrofit =
Retrofit.Builder()
.client(client)
.addConverterFactory(gsonConverterFactory)
.baseUrl("https://someauth.baseurl.com").build()
@Provides
@Singleton
@Setting //This will differentiate retrofit object
fun retrofitSetting(
client: OkHttpClient,
gsonConverterFactory: GsonConverterFactory
): Retrofit =
Retrofit.Builder()
.client(client)
.addConverterFactory(gsonConverterFactory)
.baseUrl("https://someSetting.baseurl.com").build()
//Build Api services with respect to qualifiers
@Provides
@Singleton
fun authApiService(@Auth retrofit: Retrofit): AuthApiService = retrofit.create(AuthApiService::class.java)
@Provides
@Singleton
fun settingApiService(@Setting retrofit: Retrofit): SettingApiService = retrofit.create(SettingApiService::class.java)
You Api Service classes e.g. AuthApiService and SettingApiService
interface AuthApiService {
@FormUrlEncoded
@POST("login/v2")
fun login(@FieldMap params: HashMap<String, Any>): Response<LoginResponse>
}
interface SettingApiService {
@GET("settings")
fun settings(): Response<SettingsResponse>
@GET("faqs")
fun getFAQs(): Response<FAQsResponse>
}
PS: In some cases you also need different okhttp client. In such cases, different Okhttp clients can be achieved by Qualifier
as well.
Upvotes: 17
Reputation: 2421
If you want to return Retrofit client using Dagger or Hilt, then you should use @Named
annotation. This annotation helps Hilt or Dagger understand you with the same Retrofit return type, which Retrofit instance you need to get.
Following the below way, you can provide multiple instances of retrofit with hilt or dagger.
First, here I see you have provide 2 instances of retrofit. Put the @Named
annotation for each instance of the retrofit you provide.
object AppModule {
@Singleton
@Provides
@Named("Normal")
fun provideRetrofit(gson: Gson, @ApplicationContext appContext: Context): Retrofit = ...
@Singleton
@Provides
@Named("Email")
fun provideRetrofitEmall(gson: Gson, @ApplicationContext appContext: Context): Retrofit = ...
}
Next, when you provide the api service, specify to Hilt or Dagger which retrofit instance it needs.
object AppModule {
@Provides
fun providePostsService(@Named("Normal") retrofit: Retrofit): ApiService = retrofit.create(ApiService::class.java)
@Provides
fun providePostsServiceEmall(@Named("Email") retrofit: Retrofit): EmallApiService = retrofit.create(EmallApiService::class.java)
}
And finally, clean the project and rebuild the project to see the results.
Upvotes: 49