2

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.

enter image description here

Community
  • 1
  • 1
Laurent
  • 1,661
  • 16
  • 29

1 Answers1

2

As long as you provide @Named Repository, you also need to ask for @Named Repository

@Provides
public DonutFragmentMVP.Model provideDonutFragmentModel(@Named("donutRepo") Repository repository) {
    return new DonutModel(repository);
}
azizbekian
  • 60,783
  • 13
  • 169
  • 249