Dagger/MissingBinding cannot be provided without an #Provides-annotated method - android

I am getting an exception when building from the dagger2 2.16 version to the 2.23.2 version.
It is up and running in 2.16. I didn't modify any code. After upgrading to 2.23.2, it failed to build.
I am not sure what the problem is, so I ask everyone for assistance.
Thank you.
Module
#Module
public class BaseModule {
private ConfigBuilder configBuilder;
public BaseModule(#Nullable ConfigBuilder configBuilder) {
this.configBuilder = configBuilder;
}
#Singleton
#Provides
public Gson provideGson() {
GsonBuilder builder = new GsonBuilder();
if (configBuilder != null) {
configBuilder.buildGson(builder);
}
return builder.create();
}
#Singleton
#Provides
public OkHttpClient provideOkHttpClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (configBuilder != null) {
configBuilder.buildOkHttp(builder);
}
builder.addInterceptor(new EncryptInterceptor());
if (BuildConfig.DEBUG) {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(loggingInterceptor);
}
return builder.build();
}
#Singleton
#Provides
public Retrofit provideRetrofit(OkHttpClient okHttpClient, Gson gson) {
Retrofit.Builder builder = new Retrofit.Builder()
.client(okHttpClient);
if (configBuilder != null) {
configBuilder.buildRetrofit(builder);
}
builder.addConverterFactory(GsonWrapperConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create());
return builder.build();
}
#Singleton
#Provides
public SharedPreferencesPlus provideSharedPreferencesPlus(Application application, Gson gson) {
return SharedPreferencesPlus.createDefault(application, gson);
}
#Module
interface ActivityModule {
#ActivityScope
#ContributesAndroidInjector
MainActivity main();
#Module
public interface ViewModelModule {
#Binds
#IntoMap
#ViewModelKey(VMMain.class)
ViewModel main(VMMain vm);
Component
#Singleton
#Component(modules = {BaseModule.class, AndroidSupportInjectionModule.class})
public interface BaseComponent {
Application provideApplication();
SharedPreferencesPlus provideSharedPreferencesPlus();
Gson provideGson();
OkHttpClient provideOkHttpClient();
Retrofit provideRetrofit();
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
Builder AppModule(BaseModule baseModule);
BaseComponent build();
}
#ApplicationScope
#Component(modules = {
ActivityModule.class,
ViewModelModule.class,
DataModule.class}, dependencies = BaseComponent.class)
public interface AppComponent
{
void inject(AppContext application);
}
exception:
[Dagger/MissingBinding] java.util.Map>> cannot be provided without an #Provides-annotated method.
java.util.Map>> is injected at dagger.android.DispatchingAndroidInjector(…, injectorFactoriesWithStringKeys)
dagger.android.DispatchingAndroidInjector is injected at
org.pp.va.video.app.AppContext.serviceInjector
org.pp.va.video.app.AppContext is injected at
org.pp.va.video.di.AppComponent.inject(org.pp.va.video.app.AppContext)
It is also requested at:
dagger.android.DispatchingAndroidInjector(…, injectorFactoriesWithStringKeys)

I found that starting from 2.16 to 2.17 began to have problems.
I observed the error because of the introduction of AndroidSupportInjectionModule in AppComponent. I used to introduce the AndroidSupportInjectionModule in BaseComponent, and then the BaseComponent that AppComponent dependency on. Now it won't work. I removed the introduction of AndroidSupportInjectionModule from BaseComponent and introduced AndroidSupportInjectionModule in AppComponent, which solved my problem.
My current code is as follows:
#ApplicationScope
#Component(modules = {
ActivityModule.class,
ViewModelModule.class,
DataModule.class, AndroidSupportInjectionModule.class}, dependencies = BaseComponent.class)
public interface AppComponent
#Singleton
#Component(modules = {BaseModule.class})
public interface BaseComponent {

Related

MissingBinding object in MainComponent which is provided in module in subcompnent

I use "AppComponent" which has ActivityBuilderModule and ViewModelBuilderModule and SubComponent "NetworkComponent" which has NetworkModule which provide InterfaceRequest and I inject InterfaceRequest in Repository and inject Repository in ViewModel and the ViewModel is injected in Activity but I got this error:
[Dagger/MissingBinding] InterfaceRequests cannot be provided without an #Provides-annotated method.
public interface AppComponent {
A binding with matching key exists in component: NetworkComponent
InterfaceRequests is injected at
ForYouRepository.interfaceRequests
ForYouRepositoryis injected at
NewsViewModel(newsRepository)
NewsViewModel is injected at
ViewModelBuilderModule.bindNewsViewModel(newsViewModel)
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is injected at
ViewModelFactory(creators)
tech.gplanet.shopx.di.ViewModelFactory is injected at
tech.gplanet.shopx.ui.activities.NewsActivity.viewModelFactory
tech.gplanet.shopx.ui.activities.NewsActivity
AppComponent:
#Singleton
#Component(modules = { AndroidInjectionModule.class, ActivityBuilderModule.class, ViewModelBuilderModule.class})
public interface AppComponent {
void inject(MyApplication appClass);
#Component.Builder
interface Builder {
#BindsInstance
AppComponent.Builder context(Context context);
AppComponent build();
}
NetworkComponent.Builder getNetworkComponentBuilder();
}
Network Component:
#Subcomponent(modules = {NetworkModule.class})
public interface NetworkComponent {
void inject(RegisterationActivity registerationActivity);
void inject(AuthenticationRepository repository);
void inject(ForYouRepository repository);
#Subcomponent.Builder
interface Builder {
#BindsInstance
Builder customDeserializers(#Named("custom_deserializers") GeneralCustomDeserializerInterface[] deserializers);
#BindsInstance
#Nullable
Builder baseUrl(#Named("base_url") String baseUrl);
NetworkComponent build();
}
}
Repository code:
#Inject
public InterfaceRequests interfaceRequests;
#Inject
public ForYouRepository(Context context) {
NetworkComponent networkComponent = ((MyApplication)((Activity) context).getApplication()).getAppComponent()
.getNetworkComponentBuilder()
.baseUrl(Constants.BASE_URL)
.customDeserializers(new GeneralCustomDeserializerInterface[]{})
.build();
networkComponent.inject(this);
}
Network Module:
#Provides
public Gson provideGsonBuilder(#Named("custom_deserializers") GeneralCustomDeserializerInterface [] customDeserializersList) {
GsonBuilder gsonBuilder = new GsonBuilder();
if(customDeserializersList != null) {
for(GeneralCustomDeserializerInterface customDeserializer : customDeserializersList)
gsonBuilder.registerTypeAdapter(customDeserializer.getDeserializedClass(), customDeserializer);
}
return gsonBuilder.create();
}
#Provides
public Retrofit provideRetrofitInstance(#Named("base_url") String baseURL, Gson gson) {
return new Retrofit.Builder()
.baseUrl(baseURL)
.addConverterFactory(GsonConverterFactory.create(gson))
//.callFactory(okHttpClient)
.build();
}
#Provides
public InterfaceRequests provideInterfaceRequests(Retrofit retrofit) {
return retrofit.create(InterfaceRequests.class);
}
I think you misunderstood subcomponent.
Object in a subcomponent can't be used by the component. The relation is only in the opposite direction (subcomponent can use object from the main component)
I think in your case you should use a network module in AppComponent

Dagger-2: Field not injected

My field for retrofit in this class is never injected into, it is still null when i run my code.
Here is my ServiceClass where I inject retrofit, have my api calls etc. I stripped it down for simplicity:
public class ServiceClass{
#Inject
Retrofit retrofit;
public ServiceClass(){
}
}
My module class for all network related dependencies:
#Module
public class NetworkModule {
#Provides
#ApplicationScope
Retrofit getRetrofit(OkHttpClient okHttpClient, Gson gson){
return new Retrofit.Builder()
.baseUrl(URL.BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
#Provides
#ApplicationScope
OkHttpClient getOkHttpClient(Gson gson, HttpLoggingInterceptor httpLoggingInterceptor){
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newBuilder().addInterceptor(httpLoggingInterceptor);
return okHttpClient;
}
#Provides
#ApplicationScope
HttpLoggingInterceptor getHttpLoggingInterceptor(){
return new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC);
}
#Provides
#ApplicationScope
Gson getGson(){
return new Gson();
}
}
My AppComponent this is my only component class:
#ApplicationScope
#Component(modules = {NetworkModule.class})
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(MyApplication myApplication);
AppComponent build();
}
void inject(MyApplication myApplication);
Retrofit getRetrofit();
}
My Application class:
public class MyApplication extends Application{
private AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
DaggerAppComponent
.builder()
.application(this)
.build()
.inject(this);
}
public AppComponent getAppComponent(){
return appComponent;
}
}
I tried to fiddle around the code, I don't seem to manage to get it working properly. What am I missing here?
Update (previous information still valid) :
I have noticed you incorrectly build your component: you must add .networkModule(new NetworkModule()) after DaggerAppComponent.builder()
Make sure your private AppComponent appComponent is initialized too!
For field injection (I believe that's what you're after), you can write your constructor like this:
public ServiceClass(){
MyApplication.getInstance().getAppComponent().inject(this)
}
Naturally, you should expose your appComponent entity somehow - the above is my guess (to expose appComponent entity via application entity).
PS.: better approach (and more readable too) is to avoid field injection at all and parametrize constructor (however it's not always possible, like for example if you inject into activity).
PSS.: your AppComponent should also have void inject(ServiceClass value);
There are multiple ways of injecting retrofit in ServiceClass
You have to make a separate Component for ServiceClass like :-
#Component(dependencies = AppComponent.class)
interface ServiceClassComponent {
void injectServiceClass(ServiceClass serviceClass);
}
Or
you can just inject ServiceClass into your application component:-
void injectServiceClass(ServiceClass serviceClass);
into your AppComponent
The dependencies keyword would include all the dependent components into your particular component that you would build.
Then in the constructor of ServiceClass you need to build the Component and inject it

Dagger 2 For Android "cannot be provided without an #Provides-annotated method"

I'm trying to use the latest version of Dagger 2 V2.11 for Android
Here is my code:
AppComponent:
#Singleton
#Component(modules = {
AndroidInjectionModule.class,
AppModule.class,
ActivityBuildersModule.class,
FragmentBuildersModule.class
})
public interface AppComponent {
void inject(MyApplication myApplication);
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
AppComponent build();
}
#ExceptionRequestsQualifier
ExceptionRequestsServices exceptionRequestsServices();
}
AppModule:
#Module(includes = {ActivityModule.class, FragmentModule.class})
public class AppModule {
#Provides
CompositeDisposable provideCompositeDisposable() {
return new CompositeDisposable();
}
#Provides
#ExceptionRequestsQualifier
ExceptionRequestsServices provideExceptionRequests() {
return new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(APIConstants.EXCEPTION_REQUESTS_BASE_URL)
.build()
.create(ExceptionRequestsServices.class);
}
#Singleton
#Provides
NetworkManager provideNetworkManager(Application app) {
return new NetworkManager(app);
}
}
ActivityBuildersModule:
#Module
public abstract class ActivityBuildersModule {
#ActivityScope
#ContributesAndroidInjector
abstract ExceptionRequestsActivity contributeExceptionRequestsActivity();
}
ActivityModule:
#Module()
public abstract class ActivityModule {
#Provides
#ActivityScope
static ExceptionRequestsMvpPresenter<ExceptionRequestsMvpView> bindExceptionRequestsPresenter(
ExceptionRequestsPresenter<ExceptionRequestsMvpView> presenter) {
return presenter;
}
}
FragmentBuildersModule:
#Module
public abstract class FragmentBuildersModule {
#FragmentScope
#ContributesAndroidInjector
abstract AddApplicantFragment contributeAddApplicantFragment();
#FragmentScope
#ContributesAndroidInjector
abstract PledgeFragment contributePledgeFragment();
}
FragmentModule:
#Module()
public abstract class FragmentModule {
#Provides
#FragmentScope
static AddApplicantMvpPresenter<AddApplicantMvpView> bindAddApplicantPresenter(
AddApplicantPresenter<AddApplicantMvpView> presenter) {
return presenter;
}
#Provides
#FragmentScope
static PledgeMvpPresenter<PledgeMvpView> bindPledgePresenter(
PledgePresenter<PledgeMvpView> presenter) {
return presenter;
}
}
AddApplicantPresenter:
public class AddApplicantPresenter<V extends AddApplicantMvpView> extends BasePresenter<V> implements AddApplicantMvpPresenter<V> {
#Inject
#ExceptionRequestsQualifier
ExceptionRequestsServices mExceptionRequestsServices;
#Inject
NetworkManager mNetworkManager;
#Inject
public AddApplicantPresenter(CompositeDisposable compositeDisposable) {
super(compositeDisposable);
}
}
AddApplicantMvpPresenter:
#FragmentScope
public interface AddApplicantMvpPresenter<V extends AddApplicantMvpView> extends MvpPresenter<V> {
void addApplicant(String name, String qatarId,
String date, String mobile,
ChosenImage chosenImage);
}
ActivityScope:
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface ActivityScope {
}
FragmentScope:
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface FragmentScope {
}
Error Log:
Error:(21, 1) error: mypackagename.di.component.AppComponent scoped with #Singleton may not reference bindings with different scopes:
#Provides #mypackagename.di.scope.ActivityScope mypackagename.ui.exceptionrequests.ExceptionRequestsMvpPresenter<mypackagename.ui.exceptionrequests.ExceptionRequestsMvpView> mypackagename.di.module.ActivityModule.bindExceptionRequestsPresenter(mypackagename.ui.exceptionrequests.ExceptionRequestsPresenter<mypackagename.ui.exceptionrequests.ExceptionRequestsMvpView>)
#Provides #mypackagename.di.scope.FragmentScope mypackagename.ui.addapplicant.AddApplicantMvpPresenter<mypackagename.ui.addapplicant.AddApplicantMvpView> mypackagename.di.module.FragmentModule.bindAddApplicantPresenter(mypackagename.ui.addapplicant.AddApplicantPresenter<mypackagename.ui.addapplicant.AddApplicantMvpView>)
#Provides #mypackagename.di.scope.FragmentScope mypackagename.ui.pledge.PledgeMvpPresenter<mypackagename.ui.pledge.PledgeMvpView> mypackagename.di.module.FragmentModule.bindPledgePresenter(mypackagename.ui.pledge.PledgePresenter<mypackagename.ui.pledge.PledgeMvpView>)
Modules & Components can't have different Scopes
You can have Components to have multiple Scopes and this can solve it.
Try to move it to different component and add it as component dependencies
I hope in future they can solve this, the way I've done it in my project.
Currently, Dagger2 allows module with NoScope & single scope. This should match with your components.
Thumb Rule:: Different scopes have different components.
For your application, you need three components,
FragmentComponent (FragmentScope) :- (Ideally this should be ActivityComponent)
ApplicationComponent (Singleton)
https://medium.com/#patrykpoborca/making-a-best-practice-app-4-dagger-2-267ec5f6c89a
Read more about scopes.

Retrofit cannot be provided without an #Inject constructor or from an #Provides- or #Produces-annotated method

I am learning Dagger 2 now and it's such a pain for me to explain the question without codes , so let me list all my modules, components and etc first :
App.class
public class App extends Application {
private ApiComponent mApiComponent = null;
private AppComponent mAppComponent = null;
public ApiComponent getApiComponent() {
if (mApiComponent == null) {
// Dagger%COMPONENT_NAME%
mApiComponent = DaggerApiComponent.builder()
// list of modules that are part of this component need to be created here too
.appModule(new AppModule(this)) // This also corresponds to the name of your module: %component_name%Module
.apiModule(new ApiModule(this))
.build();
}
return mApiComponent;
}
public AppComponent getAppComponent() {
if (mAppComponent == null) {
// If a Dagger 2 component does not have any constructor arguments for any of its modules,
// then we can use .create() as a shortcut instead:
mAppComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
}
return mAppComponent;
}
}
AppComponent
#Singleton
#Component(modules = AppModule.class)
public interface AppComponent {
void inject(RetrofitDemo target);
}
AppModule
private final Application mContext;
AppModule(Application context) {
mContext = context;
}
#Singleton
#ForApplication
#Provides
Application provideApplication() {
return mContext;
}
#Singleton
#ForApplication
#Provides
Context provideContext() {
return mContext;
}
ApiComponent
#Singleton
#Component(dependencies = {AppModule.class},modules = {ApiModule.class})
public interface ApiComponent {
void inject(RetrofitDemo target);
}
APIModule
#Inject
Context application;
#Inject
public ApiModule(Context context){
this.application = context;
}
#Provides
#Singleton
Gson provideGson() {
return new GsonBuilder()
// All timestamps are returned in ISO 8601 format:
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
// Blank fields are included as null instead of being omitted.
.serializeNulls()
.create();
}
#Provides
#Singleton
OkHttpClient provideOkHttpClient() {
...
}
#Provides
#Singleton
public Retrofit provideRetrofit(Gson gson,OkHttpClient okHttpClient){
return new Retrofit.Builder()
.baseUrl(DribbleApi.END_POINT)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(okHttpClient)
.build();
}
And my activity will be like this:
#Inject
Retrofit mRetrofit;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_retrofit_demo);
((App) getApplication()).getApiComponent().inject(this);
...
Here is the error message:
Error:(18, 10) : retrofit2.Retrofit cannot be provided without an #Inject constructor or from an #Provides- or #Produces-annotated method.
retrofit2.Retrofit is injected at com.sinyuk.yuk.RetrofitDemo.mRetrofit
com.sinyuk.yuk.RetrofitDemo is injected at com.sinyuk.yuk.AppComponent.inject(target)
What makes me confused is the retrofit instance is provided by the ApiModule, but why the error massage said it's injected at appComponent?And I can't find any place wrong in my code. T_T,it's too heavy going to learn Dagger for me...I think.
Besides, in my case I wrote dependencies = AppModule.class module = ApiModule.class in the AppComponent , and it seems to be right I think,but if I wrote module = ({AppComponent.class,ApiComponent.class}),it also works fine.Anybody can explain me why?
Kindly review my code and give me some advice. Thx in advance!
#Sinyuk There's a lot to unpack here, and Dagger is a little complicated at first blush, but I think I can help. First, you have a conceptual misunderstanding regarding the #Component annotation. A Component is an interface which you define, and which Dagger implements through code generation. You will define the interface, and annotate it with #Component and then you will provide a set of Modules to Dagger to use in the generation process. The modules which you use are passed in through the modules element of the #Component annotation. If you want to have one Component permit another Component to support the injection process, then any Component interfaces which you need to have Dagger use while injecting your code, will be passed in through the dependencies element of the #Component annotation.
--
As a result, The following is incorrect
#Component(dependencies = AppModule.class module = ApiModule.class`)
instead, to have the one Component use two Modules write:
#Component(modules = {ApiModule.class, AppModule.class})
or, to have one Component use one Module and depend upon the other Component
#Component(modules = {AppModule.class}, dependencies = {ApiComponent.class})
I hope that that helps you get onto the right path. Let me know if you have any follow up questions.
Okay so your configuration should be this
public class App extends Application {
private AppComponent mAppComponent = null;
public AppComponent getAppComponent() {
if (mAppComponent == null) {
// If a Dagger 2 component does not have any constructor arguments for any of its modules,
// then we can use .create() as a shortcut instead:
mAppComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
}
return mAppComponent;
}
}
And
#Singleton
#Component(modules = {AppModule.class, ApiModule.class})
public interface AppComponent {
void inject(RetrofitDemo target);
}
And
#Module
public class AppModule {
private final Application mContext;
AppModule(Application context) {
mContext = context;
}
#Provides
Application provideApplication() {
return mContext;
}
#Provides
Context provideContext() {
return mContext;
}
}
And
#Module
public class ApiModule {
#Provides
#Singleton
Gson provideGson() {
return new GsonBuilder()
// All timestamps are returned in ISO 8601 format:
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
// Blank fields are included as null instead of being omitted.
.serializeNulls()
.create();
}
#Provides
#Singleton
OkHttpClient provideOkHttpClient() {
...
}
#Provides
#Singleton
public Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient){
return new Retrofit.Builder()
.baseUrl(DribbleApi.END_POINT)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(okHttpClient)
.build();
}
}
And
//...Activity
#Inject
Retrofit mRetrofit;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_retrofit_demo);
((App) getApplication()).getAppComponent().inject(this);
...

Dagger ApplicationComponent must be set

I need to expose my OkHttpClient from ApplicationModule so I added to ApplicationComponent. Something like this :
#Module
public class ApplicationModule {
#Provides #Singleton
public OkHttpClient provideOkHttpClient() {
final OkHttpClient.Builder client = new OkHttpClient.Builder();
return client.build();
}
#Singleton
#Component( modules = {ApplicationModule.class} )
public interface ApplicationComponent {
OkHttpClient okHttpClient();
}
so I added the OkHttpClient okHttpClient(); in the ApplicationComponent as you can see right above.
Now in my NetworkModule I use it like :
#Module
public class NetworkModule {
#Provides #ActivityScope
public ProjectService provideProjectService(OkHttpClient client) {
return new ProjectService(client);
}
#Component( dependencies = {ApplicationComponent.class}, modules = {NetworkModule.class} )
#ActivityScope
public interface NetworkComponent {
void inject(#NonNull MyActivity myActivity);
}
but now when I get a runtime error :
Caused by: java.lang.IllegalStateException: css.test.demo.ApplicationComponent must be set
at css.test.demo.main.projects.network.DaggerNetworkComponent$Builder.build(DaggerNetworkComponent.java:102)
at css.test.demo.main.projects.MyActivity.onCreate(MyActivity.java:159)
at android.app.Activity.performCreate(Activity.java:6237)
and here is how I build it in MyActivity :
NetworkComponent = DaggerNetworkComponent.builder()
.NetworkModule(new NetworkModule(this))
.build();
NetworkComponent.inject(this);
I like to emphasize that dagger contains no magic—its is just plain java. If you don't give it the information it needs, the compiler will complain.
If you have a look at your DaggerNetworkComponent.Builder you will notice that it has a method called appComponent(AppComponent component). This is where dagger expects you to add the appcomponent that your NetworkComponent depends on.
NetworkComponent = DaggerNetworkComponent.builder()
.NetworkModule(new NetworkModule(this))
.appComponent(((App)getApplication()).getAppComponent()) // add your appComponent
.build();
And it should work.

Categories

Resources