Lyofen Lyofen - 2 months ago 28
Java Question

Android Dagger2 error: @javax.inject.Named("BaseUrl") java.lang.String is bound multiple times

I'm trying some things with Dagger2 but still difficult to understand..

I would like to use 2 services in 2 classes, SplashActivity and HomeActivity.
Services depends on NetModule because i would like reuse retrofit and okhttpclient provides.

Here is my NetModule :

@Module
public class NetModule {
@Provides
Retrofit provideRetrofit(@Named("BaseUrl") String baseUrl, OkHttpClient okHttpClient) {
return new Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
}

@Provides
HttpLoggingInterceptor provideHttpLoggingInterceptor() {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
if (BuildConfig.DEBUG) {
logging.setLevel(HttpLoggingInterceptor.Level.HEADERS);
} else {
logging.setLevel(HttpLoggingInterceptor.Level.NONE);
}

return logging;
}

@Provides
OkHttpClient provideOkHttpClient(HttpLoggingInterceptor httpLoggingInterceptor, @Named("ConnectTimeoutMs") int connectTimeoutMs, @Named("ReadTimeoutMs") int readTimeoutMs) {
return new OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor)
.connectTimeout(connectTimeoutMs, TimeUnit.MILLISECONDS)
.readTimeout(readTimeoutMs, TimeUnit.MILLISECONDS)
.build();
}
}


StaticDataModule and StatusModule, it's 2 differents API so they use NetModule :

@Module(includes = NetModule.class)
public class StaticDataModule {
@Provides
@Singleton
StaticDataService provideStaticDataService(Retrofit retrofit) {
return new RetrofitStaticDataService(retrofit);
}

@Provides
@Named("BaseUrl")
String provideBaseUrl() {
return "http://url_static.com";
}

@Provides
@Named("ConnectTimeoutMs")
int provideConnectTimeoutMs() {
return 5000;
}

@Provides
@Named("ReadTimeoutMs")
int provideReadTimeoutMs() {
return 5000;
}
}

@Module(includes = NetModule.class)
public class StatusModule {
@Provides
@Singleton
StatusService provideStatusService(Retrofit retrofit) {
return new RetrofitStatusService(retrofit);
}

@Provides
@Named("BaseUrl")
String provideBaseUrl() {
return "http://url_status.com";
}

@Provides
@Named("ConnectTimeoutMs")
int provideConnectTimeoutMs() {
return 5000;
}

@Provides
@Named("ReadTimeoutMs")
int provideReadTimeoutMs() {
return 5000;
}
}


And i build them in this component :

@Singleton
@Component(modules = {AppModule.class, StaticDataModule.class, StatusModule.class})
public interface AppComponent {
void inject(SplashActivity splashActivity);
void inject(HomeActivity homeActivity);
}


I obtain this error : @javax.inject.Named("BaseUrl") java.lang.String is bound multiple times.
I understand my error, dagger dont know who provide between StaticData baseUrl and Status baseUrl.

I tried to make 2 components, StaticDataComponent and StatusComponent, but i can't inject both in the same activity.

I tried to extends NetModule in StaticDataModule and StatusModule, and give parameters with constructor, but multiple bounds error was on retrofit provide.

So i don't know how to reuse NetModule with differents parameters in 2 modules, if someone has an example it should really help me.

Thanks !

Answer

Do not include NetModule.class as dependency to your modules, just include them separately in the component.

@Module(includes = NetModule.class)
public class StaticDataModule {

to

@Module
public class StaticDataModule {

And then use like this:

@Component(modules = {
    NetModule.class, StaticDataModule.class
}) public interface FirstComponent {
  void inject(WhateverYouWantActivity activity);
}

@Component(modules = {
    NetModule.class, StatusModule.class
}) public interface FirstComponent {
  void inject(WhateverYouWantSecondActivity activity);
}

If you have to inject into the same activity, you better rework your architecture, but if you still want to do this, you can get rid of inject method, and add something like this:

@Component(modules = { /* your modules */ }) public interface YourComponent {

  Retrofit getRetrofit();

  OkHttpClient getOkHttpClient();
}

And use it accordingly:

retrofit = yourComponentBuiltByDagger.getRetrofit();

Instead of:

@Inject Retrofit retrofit;
Comments