I'm newbie to use Dagger2
on android. i create some class as Dagger module which they are using context
, i can't merge,combine or using single context for other modules which they need that. and i get this error now:
android.content.Context is bound multiple times
SpModules:
@Module
public class SpModules {
private Context context;
public SpModules(Context context) {
this.context = context;
}
@Provides // this can be non-scoped because anyway the same instance is always returned
Context provideContext() {
return this.context;
}
@Provides
@Singleton
SP provideSharePreferences(Context context) {
return new SP(context); // use method-local Context
}
}
RealmModule
:
@Module
public class RealmModule {
private Context context;
@Provides
Context provideApplicationContext() {
return AlachiqApplication.getInstance();
}
@Provides
@Singleton
RealmConfiguration provideRealmConfiguration() {
final RealmConfiguration.Builder builder = new RealmConfiguration.Builder()
.schemaVersion(Migration.SCHEMA_VERSION)
.deleteRealmIfMigrationNeeded()
.migration(new Migration());
return builder.build();
}
@Provides
Realm provideDefaultRealm(RealmConfiguration config) {
return Realm.getInstance(config);
}
@Provides
Context provideContext() {
return this.context;
}
}
Component:
@Component(modules = {RealmModule.class, SpModules.class})
@Singleton
public interface ApplicationComponent {
void inject(ActivityRegister target);
void inject(ActivityMain target);
void inject(ActivityBase target);
void inject(FragmentAlachiqChannels target);
void inject(SocketServiceProvider target);
}
and then Application class to make Dagger2:
component = DaggerApplicationComponent.builder()
.appModules(new SpModules(this))
.build();
how can i resolve this problem?
That's simply dagger telling you that you're providing several times the same class to your component. In fact you do it here as well as across different modules for the same component:
@Provides
Context provideApplicationContext() {
return AlachiqApplication.getInstance();
}
@Provides
Context provideContext() {
return this.context;
}
These methods are different, but they're providing the same dependency and without extra info dagger is not able to determine which Context
to use.
You got a couple of options. If a single context would be enough to serve all your classes, then you could simply remove the extra provide methods.
However, let's say you need both application and some other context. You can use the annotation Named
. Here's how it works, you annotate your provide methods with this annotation which basically will give a name to the dependency. Like so:
@Module
public class SpModules {
// ...
@Provides
@Named("context")
Context provideContext() {
return this.context;
}
//...
}
@Module
public class RealmModule {
//...
@Provides
@Named("application.context")
Context provideApplicationContext() {
return AlachiqApplication.getInstance();
}
//...
}
Now you need to also annotated when you use these dependencies, for example say you have an object that depends on the application context:
public class Something {
public Something(@Named("application.context") Context context) {
//...
}
}
Or as a field:
public class Something {
@Named("application.context") Context context;
// ...
}
Or even in your module:
@Provides
@Singleton
SP provideSharePreferences(@Named("context") Context context) {
return new SP(context);
}
The name can be anything you want as long as they're consistent.
An alternative is to use Qualifiers
. They work similar to the Named
annotation, but are different. You'll be qualifying the dependency. So say you create 2 qualifiers:
@java.lang.annotation.Documented
@java.lang.annotation.Retention(RUNTIME)
@javax.inject.Qualifier
public @interface InstanceContext {
}
@java.lang.annotation.Documented
@java.lang.annotation.Retention(RUNTIME)
@javax.inject.Qualifier
public @interface ApplicationContext {
}
You can then use these to annotate the provide methods:
@Module
public class SpModules {
// ...
@Provides
@InstanceContext
Context provideContext() {
return this.context;
}
//...
}
@Module
public class RealmModule {
//...
@Provides
@ApplicationContext
Context provideApplicationContext() {
return AlachiqApplication.getInstance();
}
//...
}
You then use it the same way as with name. Here are the examples:
public class Something {
public Something(@ApplicationContext Context context) {
//...
}
}
public class Something {
@ApplicationContext Context context;
// ...
}
@Provides
@Singleton
SP provideSharePreferences(@InstanceContext Context context) {
return new SP(context);
}
Again, these names can be anything. I personally didn't put a lot of effort in thinking about them. Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With