I am using Dagger2
in my android application, I have two component in my application. First is global for entire application and second is specific to activity instance.
NetComponent.java
@Singleton
@Component(modules = {AppModule.class, NetModule.class})
public interface NetComponent {
void inject(AuthenticationActivity authenticationActivity);
void inject(PaymentActivity paymentActivity);
}
ValidationComponent.java
@Singleton
@Component(modules = {ValidatorModule.class})
public interface ValidationComponent {
void inject(Activity activity);
}
AppModule.java
@Module
public class AppModule {
private Application application;
public AppModule(Application application) {
this.application = application;
}
@Provides
@Singleton
Application providesApplication() {
return application;
}
}
NetModule.java
@Module
public class NetModule {
@Provides
@Singleton
SharedPreferences providesSharedPreferences(Application application) {
return PreferenceManager.getDefaultSharedPreferences(application);
}
@Provides
@Singleton
Cache provideOkHttpCache(Application application) {
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(application.getCacheDir(), cacheSize);
return cache;
}
@Provides
@Singleton
Gson provideGson() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
return gsonBuilder.create();
}
@Provides
@Singleton
OkHttpClient provideOkHttpClient(Cache cache) {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newBuilder()
//.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
.cache(cache)
.build();
return okHttpClient;
}
@Provides
@Singleton
@Named("authRetrofit")
Retrofit provideAuthRetrofit(Gson gson, OkHttpClient okHttpClient) {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(PAYMENT_SERVICE)
.client(okHttpClient)
.build();
return retrofit;
}
@Provides
@Singleton
@Named("paymentRetrofit")
Retrofit providePaymentRetrofit(Gson gson, OkHttpClient okHttpClient) {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(LOGIN_SERVICE)
.client(okHttpClient)
.build();
return retrofit;
}
}
ValidatorModule.java
@Module
public class ValidatorModule {
private final Activity activity;
public ValidatorModule(Activity activity) {
this.activity = activity;
}
@Provides
com.mobsandgeeks.saripaar.Validator providesValidator() {
return new com.mobsandgeeks.saripaar.Validator(activity);
}
}
AppApplication.java
public class AppApplication extends Application {
private NetComponent mNetComponent;
@Override
public void onCreate() {
super.onCreate();
mNetComponent = DaggerNetComponent.builder()
.appModule(new AppModule(this))
.build();
}
public NetComponent getmNetComponent() {
return mNetComponent;
}
}
AuthenticationActivity.java
public class AuthenticationActivity extends BaseActivity implements View.OnClickListener, Validator.ValidationListener {
@Inject
Validator validator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
((AppApplication) getApplication()).getmNetComponent().inject(this);
ValidationComponent validationComponent = DaggerValidationComponent.builder()
.validatorModule(getValidatorModule())
.build();
validationComponent.inject(this);
...
// apply click and validation listeners
validator.setValidationListener(this);
}
}
protected ValidatorModule getValidatorModule() {
return new ValidatorModule(this);
}
It is generating ValidationComponent
but not DaggerNetComponent
Above are my module, components of my application. When I am compiling and building a application then I am getting below errors -
Error
Information:Gradle tasks [clean, :app:generateDebugSources, :app:mockableAndroidJar, :app:prepareDebugUnitTestDependencies, :app:generateDebugAndroidTestSources, :app:compileDebugSources, :app:compileDebugUnitTestSources, :app:compileDebugAndroidTestSources]
C:\Users\xyz\AndroidStudioProjects\ICICIAppathon\app\src\main\java\com\icici\iciciappathon\AppApplication.java
Error:(24, 48) error: cannot find symbol class DaggerNetComponent
C:\Users\xyz\AndroidStudioProjects\ICICIAppathon\app\src\main\java\com\icici\iciciappathon\login\AuthenticationActivity.java
Error:(35, 48) error: cannot find symbol class DaggerValidationComponent
Error:(39, 43) error: package com.icici.iciciappathon.databinding does not exist
C:\Users\xyz\AndroidStudioProjects\ICICIAppathon\app\src\main\java\com\icici\iciciappathon\checkout\PaymentActivity.java
Error:(28, 43) error: package com.icici.iciciappathon.databinding does not exist
C:\Users\xyz\AndroidStudioProjects\ICICIAppathon\app\src\main\java\com\icici\iciciappathon\dashboard\DashboardActivity.java
Error:(32, 43) error: package com.icici.iciciappathon.databinding does not exist
C:\Users\xyz\AndroidStudioProjects\ICICIAppathon\app\src\main\java\com\icici\iciciappathon\shopping\ScanBarcodeActivity.java
Error:(41, 43) error: package com.icici.iciciappathon.databinding does not exist
C:\Users\xyz\AndroidStudioProjects\ICICIAppathon\app\src\main\java\com\icici\iciciappathon\ui\GetStartedActivity.java
Error:(27, 43) error: package com.icici.iciciappathon.databinding does not exist
C:\Users\xyz\AndroidStudioProjects\ICICIAppathon\app\src\main\java\com\icici\iciciappathon\dagger\component\NetComponent.java
Error:(34, 10) error: com.mobsandgeeks.saripaar.Validator cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
com.icici.iciciappathon.login.AuthenticationActivity.validator
[injected field of type: com.mobsandgeeks.saripaar.Validator validator]
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.
Information:BUILD FAILED
Information:Total time: 11.373 secs
Information:9 errors
Information:0 warnings
Information:See complete output in console
The general statement here is that Dagger doesn't generate classes when it encounters an error, usually when you're doing something impossible in your binding graph. That's the case here.
C:\Users\xyz\AndroidStudioProjects\ICICIAppathon\app\src\main\java\com\icici\iciciappathon\dagger\component\NetComponent.java Error:(34, 10) error: com.mobsandgeeks.saripaar.Validator cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method. com.icici.iciciappathon.login.AuthenticationActivity.validator [injected field of type: com.mobsandgeeks.saripaar.Validator validator]
I agree with azizbekian that the problem is that you are trying to inject the Validator from within AuthenticationActivity, and telling NetComponent to try to do so without instructing it how to do so (in ValidationModule).
In the code you've posted, there isn't a reason for NetComponent to inject AuthenticationActivity; there's nothing for it to provide. So you can delete these two lines and be done:
// In NetComponent
void inject(AuthenticationActivity authenticationActivity);
// In AuthenticationActivity
((AppApplication) getApplication()).getmNetComponent().inject(this);
However, it's also possible that you've simply not shown us the NetComponent dependencies you need in AuthenticationActivity. In that case, you're going to need to combine the object graphs, either through subcomponents or component dependencies. You'll still need to delete the two lines listed above, because under no circumstance does NetComponent have the dependencies it needs to inject AuthenticationActivity.
To do so with subcomponents, simply make a builder on NetComponent through which you get your ValidationActivity. You're welcome to provide a scope, but you don't necessarily need one, and I think it might be confusing to add that into the mix. At that point, your ValidationComponent will have access to all the bindings in your NetComponent AND all of the bindings listed in ValidationComponent. This is effectively identical to azizbekian's answer, though notably this is through subcomponents, not component dependencies. I'll talk about component dependencies in a moment.
// After removing the inject(AuthenticationActivity) call, add this to NetComponent
ValidatorComponent validatorComponent(ValidatorModule validatorModule);
// And call the implementation from AuthenticationActivity
((AppApplication) getApplication()).getmNetComponent()
.validatorModule(new ValidatorModule(this))
.inject();
You'll also need to switch ValidationComponent
from @Component
to @Subcomponent
, and remove the @Singleton
instance (which makes sense because you're creating a new one for every AuthenticationActivity instance Android creates.
Effectively, this turns NetComponent into a factory for ValidationComponent instances. Dagger generates the code for both at once, so ValidationComponent can access anything it needs from NetComponent automatically. However, this way it is impossible to generate code for each one separately, or to get a ValidationComponent without a NetComponent instance (except through including it in another component).
Component dependencies work a little bit differently. They're freestanding components, so they can be generated separately and independently. Instead, you can pass in an interface (often but not necessarily another Dagger component like NetComponent), and every single no-argument method becomes an automatic provider into the other graph. This means, for example, that you could list specific dependencies available to ValidationComponent from NetComponent, add a dependencies={NetComponent.class}
to your ValidationComponent definition, and then change your DaggerValidationComponent builder to call .netComponent(((AppApplication getApplication()).getmNetComponent())
to hook the exact instances up. (Similarly, you could do so with any implementation of that interface, whether Dagger generates it or not; this can help with testing.) You'll also need to remove the use of @Singleton
, because Dagger would be very confused to have two separate components both claim to exist in singleton scope—one has to be created first, after all.
You haven't listed out the exact dependencies you're consuming out of NetComponent, so I don't have example changes I can show. However, for cases like this, I would recommend using subcomponents anyway; the bindings are more automatic, you likely won't benefit from the loose coupling you'd get from component dependencies, and you're closer to the design of Dagger's official Android support package so it's easier to migrate to that later.