I'm using MVP pattern with Dagger 2.
My project has two features using a common repository. It means I have to inject two times this repository, one time for each feature. But when It tried to do this I get this error : "...Repository is bound multiple times"
I found that this can be resolved using @Named
. So I added this in my module but now I'm getting a new error "...Repository cannot be provided without an @Provides-annotated
method."
I think I have to add this @Named
elsewhere in my project to make it work properly since I got some link explaining this (like this one multiple instance of same object with named). The problem I'm quite new to all this and can't find where to add this @Names
elsewhere in my project architecture.
So, I'm actually getting this error "...Repository cannot be provided without an @Provides-annotated method."
My project is structured like following.
==== A root package containing this three classes :
App class
public class App extends Application {
private ApplicationComponent component;
@Override
public void onCreate() {
super.onCreate();
final String AUTH_TOKEN = getResources().getString(R.string.aqicn_token);
final String BASE_URL = getResources().getString(R.string.aqicn_api_base_url);
component = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.pollutionApiModule(new PollutionApiModule(BASE_URL))
.pollutionLevelsModule(new PollutionLevelsModule())
.build();
}
public ApplicationComponent getComponent() {
return component;
}
}
ApplicationComponent class
@Singleton
@Component(modules = {ApplicationModule.class, PollutionApiModule.class, PollutionLevelsModule.class, DonutModule.class})
public interface ApplicationComponent {
void injectPollutionLevels(PollutionLevelsFragment target);
void injectDonut(DonutFragment target);
}
ApplicationModule class
@Module
public class ApplicationModule {
private Application application;
public ApplicationModule(Application application) {
this.application = application;
}
@Provides
@Singleton
public Context provideContext() {
return application;
}
}
==== A pollutionlevels package containing a Dagger module, this package is MVP structured (Fragment, Model, Module, Presenter...) and is related to a single feature that get data from my common repository. The purpose of this feature is to show my data as text :
PollutionLevelModule class, you can see here I tried to add the @Name annotation trying to resolve my problem :
@Module
public class PollutionLevelsModule {
@Provides
public PollutionLevelsFragmentMVP.Presenter providePollutionLevelsFragmentPresenter(PollutionLevelsFragmentMVP.Model pollutionLevelsModel) {
return new PollutionLevelsPresenter(pollutionLevelsModel);
}
@Provides
public PollutionLevelsFragmentMVP.Model providePollutionLevelsFragmentModel(Repository repository) {
return new PollutionLevelsModel(repository);
}
@Singleton
@Provides
@Named("levelsRepo")
public Repository provideRepo(PollutionApiService pollutionApiService) {
return new CommonRepository(pollutionApiService);
}
}
This package contains a Fragment where I inject the repository in onActivityCreated()
. Here I call the method injectPollutionLevels()
implemented in my App class (the class I shew you just above) :
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
((App) getActivity().getApplication()).getComponent().injectPollutionLevels(this);
}
==== A donut package containing a Dagger module, this package is MVP structured (Fragment, Model, Module, Presenter...) and is related to a single feature that get data from my common repository. The purpose of this feature is to show my data as chart :
DonutModule class, you can see here I tried to add the @Name annotation trying to resolve my problem :
@Module
public class DonutModule {
@Provides
public DonutFragmentMVP.Presenter providedDonutFragmentPresenter(DonutFragmentMVP.Model donutModel) {
return new DonutPresenter(donutModel);
}
@Provides
public DonutFragmentMVP.Model provideDonutFragmentModel(Repository repository) {
return new DonutModel(repository);
}
@Singleton
@Provides
@Named ("donutRepo")
public Repository provideRepo(PollutionApiService pollutionApiService) {
return new CommonRepository(pollutionApiService);
}
}
This package contains a Fragment where I inject the repository in onActivityCreated()
. Here I call the method injectDonut()
implemented in my App class (the class I shew you just above) :
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
((App) getActivity().getApplication()).getComponent().injectDonut(this);
}
==== A common package containing my Repository
public class CommonRepository implements Repository {
private PollutionApiService pollutionApiService;
public CommonRepository(PollutionApiService pollutionApiService) {
this.pollutionApiService = pollutionApiService;
}
@Override
public Observable<Aqicn> getDataFromNetwork(String city, String authToken) {
Observable<Aqicn> aqicn = pollutionApiService.getPollutionObservable(city, authToken);
return aqicn;
}
}
This is a screenshot of my architecture if that can help you to point better how to solve this. Let me know if you need more source code. Thank you.