Dagger 2 cannot be provided without the @Provides-annotated method
I
know there are a lot of similar problems, but I still can’t find a solution to the problem, and at this stage, I have no idea. I have the following settings:
- Application modules/components: Used only for context and application objects.
- Network modules/components: Retrofit clients
- : A module/component used to inject dependencies in the MVP screen. I want to inject Presenter and Interactor into the fragment.
- PlaceRequests: Transform the interface
City module/component
The code looks like this:
ApplicationModule.java
@Module
public class ApplicationModule {
private Application mApp;
public ApplicationModule(Application app) {
mApp = app;
}
@Provides
@Singleton
public Application provideApplication() {
return mApp;
}
@Provides
@Singleton
Context provideApplicationContext() {
return mApp.getApplicationContext();
}
}
ApplicationComponent.java
@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
Application application();
Context getContext();
}
NetModule.java
@Module
public class NetModule {
String mBaseUrl;
public NetModule(String baseUrl) {
this.mBaseUrl = baseUrl;
}
@Provides
@Singleton
SharedPreferences providesSharedPreferences(Application application) {
return PreferenceManager.getDefaultSharedPreferences(application);
}
@Provides
@Singleton
Cache provideOkHttpCache(Application application) {
int cacheSize = 10 * 1024 * 1024; 10 MiB
return new Cache(application.getCacheDir(), cacheSize);
}
@Provides
@Singleton
OkHttpClient provideOkHttpClient(Cache cache) {
OkHttpClient client = new OkHttpClient();
client.setCache(cache);
return client;
}
@Provides
@Singleton
Retrofit provideRetrofit(OkHttpClient okHttpClient) {
return new Retrofit.Builder()
.addConverterFactory(JacksonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(mBaseUrl)
.client(okHttpClient)
.build();
}
@Provides
@Singleton
PlaceRequests providePlaceRequests(Retrofit retrofit) {
return retrofit.create(PlaceRequests.class);
}
}
NetComponent.java
@Singleton
@Component(
dependencies = {ApplicationModule.class},
modules = {NetModule.class}
)
public interface NetComponent {
Application application();
PlaceRequests getPlaceRequests();
}
CityModule.java
@Module
public class CityModule {
private CityMvp.View view;
public CityModule(CityMvp.View view) {
this.view = view;
}
@Provides
public CityMvp.View provideView() {
return view;
}
@Provides
public CityMvp.Interactor provideInteractor(PlaceRequests placeRequests) {
return new CityInteractor(placeRequests);
}
@Provides
public CityPresenter providePresenter(CityMvp.View cityView, CityMvp.Interactor interactor) {
return new CityPresenter(cityView, interactor);
}
}
CityComponent.java
@PerFragment
@Component(
dependencies = {NetModule.class},
modules = {CityModule.class}
)
public interface CityComponent {
void inject(CityFragment cityFragment);
}
CityInteractor .java (unable to inject causes PlaceRequests dependency).
public class CityInteractor implements CityMvp.Interactor {
private PlaceRequests placeRequests;
public CityInteractor(PlaceRequests placeRequests) {
this.placeRequests = placeRequests;
}
@Override
public void getPlaceDetails(String placeId, String key, Subscriber<PlaceDetails> subscriber) {
Observable<PlaceDetails> observable = placeRequests.getPlaceDetails(placeId, key);
observable.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(subscriber);
}
}
Finally, the error trajectory:
: error: com.blabla.blabla.webapi.place.PlaceRequests cannot be provided without an @Provides-annotated method.
void inject(CityFragment cityFragment);
^
com.blabla.blabla.screens.city.CityFragment.presenter
[injected field of type: com.blabla.blabla.screens.city.CityPresenter presenter]
com.blabla.blabla.di.modules.CityModule.providePresenter(com.blabla.blabla.screens.city.CityMvp.View cityView, com.blabla.blabla.screens.city.CityMvp.Interactor interactor)
[parameter: com.blabla.blabla.screens.city.CityMvp.Interactor interactor]
com.blabla.blabla.di.modules.CityModule.provideInteractor(com.blabla.blabla.webapi.place.PlaceRequests placeRequests)
[parameter: com.blabla.blabla.webapi.place.PlaceRequests placeRequests]
3 errors
:app:compileDebugJavaWithJavac FAILED
FAILURE: Build failed with an exception.
As far as I know, I expose the PlaceRequests object in NetComponent.java, and NetModule.java is a dependency of CityComponent. Why can’t I get the PlaceRequests dependency from CityComponent? What am I missing? Thanks!
Solution
Component dependencies Specifying by @Component(dependencies={...})
should not be modules because you own them. They should be types (usually components) that provide dependencies through zero-parameter methods called offering methods.
Switch your dependencies to components instead of modules.
If it helps, you may want to change the way you think about components, modules, and component dependencies. You can think of Dagger as creating object graphs where modules define the inputs or bindings (bind) of the graph, and components define the output or consumers of the graph. This makes component dependencies type or component inclusion or import from another external source, which may contain components created by different Daggers, but may not contain modules — rather than relying on modules that you will depend on the component that uses that module.