CustomScope may not reference bindings with different scopes - android

I am new to dagger, I have defined my application component like this
#Singleton
#Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void inject(BaseActivity activity);
Context context();
}
This is my ApplicationModule
#Module
public class ApplicationModule {
public TipoApplication application;
public ApplicationModule(TipoApplication application) {
this.application = application;
}
#Singleton
#Provides
public Context provideContext(){return application.getApplicationContext();}
#Singleton
#Provides
public SharedPreferences provideSharedPreferences(Context context){
return PreferenceManager.getDefaultSharedPreferences(context);
}
#Singleton
#Provides
public Gson provideGson(){
return new Gson();
}
#Singleton
#Provides
public SharedPrefsManager provideSharedPrefsManager(SharedPreferences sharedPreferences, Gson gson){
return new SharedPrefsManager(sharedPreferences, gson);
}
}
I have created a dependent Component LocationProviderComponent
#LocationScope
#Component(dependencies = {ApplicationComponent.class},modules = {LocationProviderModule.class})
public interface LocationProviderComponent {
void inject(LocationRepository locationRepository);
}
And Finally My LocationProviderModule
#Module
public class LocationProviderModule {
#Singleton
#Provides
FusedLocationProviderClient provideFusedLocationProviderClient(Context context) {
return LocationServices.getFusedLocationProviderClient(context);
}
#Singleton
#Provides
LocationRequest provideLocationRequest() {
return new LocationRequest()
.setInterval(5000)
.setFastestInterval(60000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
#Singleton
#Provides
LocationSettingsRequest provideLocationSettingRequest(LocationRequest mLocationRequest) {
return new LocationSettingsRequest.Builder().addLocationRequest(mLocationRequest).build();
}
}
I am getting 2 errors when I build.
1st cannot find symbol class DaggerApplicationComponent
2nd
LocationProviderComponent scoped with LocationScope may not reference bindings with different scopes:
#Singleton #Provides FusedLocationProviderClient LocationProviderModule.provideFusedLocationProviderClient(android.content.Context)
#Singleton #Provides LocationRequest .module.LocationProviderModule.provideLocationRequest()
Please tell me what I am doing wrong.

Any module's #Provides method may only have the same scope as the component they are part of. Read more here.
In your case LocationProviderModule is part of the LocationProviderComponent which is scoped with #LocationScope whereas the provides methods in that module uses the #Singleton scope. This is exactly what Dagger is complaining about:
LocationProviderComponent scoped with LocationScope may not reference
bindings with different scopes
It is also pointing to where the problem is:
#Singleton #Provides FusedLocationProviderClient LocationProviderModule.provideFusedLocationProviderClient(android.content.Context)
#Singleton #Provides LocationRequest.module.LocationProviderModule.provideLocationRequest()
Instead of using #Singleton, you just need to use #LocationScope in the LocationProviderModule.

Related

Dagger 2 error Subcomponent may not reference scoped bindings

I am using Dagger2 in my app to provide dependencies. I get this following error when I build my app.
e: /Users/sriramr/Desktop/android/Movie/MovieInfo/app/build/generated/source/kapt/debug/in/sriram/movieinfo/di/ActivityBuilder_BindMoviesListActivity.java:22: error: in.sriram.movieinfo.di.ActivityBuilder_BindMoviesListActivity.MoviesListActivitySubcomponent (unscoped) may not reference scoped bindings:
#Subcomponent(modules = MoviesListActivityModule.class)
^
#Provides #Singleton in.sriram.movieinfo.network.TmdbService in.sriram.movieinfo.di.MoviesListActivityModule.getTmdbService(retrofit2.Retrofit)
#Provides #Singleton retrofit2.Retrofit in.sriram.movieinfo.di.NetworkModule.getRetrofit(okhttp3.OkHttpClient, retrofit2.converter.gson.GsonConverterFactory, retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory)
#Provides #Singleton okhttp3.OkHttpClient in.sriram.movieinfo.di.NetworkModule.getOkHttpClient(okhttp3.logging.HttpLoggingInterceptor, okhttp3.Cache)
#Provides #Singleton okhttp3.logging.HttpLoggingInterceptor in.sriram.movieinfo.di.NetworkModule.getHttpLoggingInterceptor()
#Provides #Singleton okhttp3.Cache in.sriram.movieinfo.di.NetworkModule.getCacheFile(#Named("application-context") android.content.Context)
#Provides #Singleton retrofit2.converter.gson.GsonConverterFactory in.sriram.movieinfo.di.NetworkModule.getGsonConverterFactory()
#Provides #Singleton retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory in.sriram.movieinfo.di.NetworkModule.getRxJavaFactory()
#Provides #Singleton in.sriram.movieinfo.cache.AppDatabase in.sriram.movieinfo.di.ContextModule.getAppDatabase(#Named("application-context") android.content.Context)
#Provides #Singleton com.squareup.picasso.Picasso in.sriram.movieinfo.di.MoviesListActivityModule.getPicasso(#Named("application-context") android.content.Context)
This is my ContextModule
#Module
public class ContextModule {
#Provides
#Named("application-context")
Context getContext(Application app) {
return app;
}
#Provides
#Singleton
AppDatabase getAppDatabase(#Named("application-context") Context context) {
return Room.databaseBuilder(context,
AppDatabase.class, "database-name").build();
}
}
And this is my NetworkModule
#Module(includes = ContextModule.class)
public class NetworkModule {
#Provides
#Singleton
Cache getCacheFile(#Named("application-context") Context context) {
File cacheFile = new File(context.getCacheDir(), "moviedb-cache");
return new Cache(cacheFile, 10 * 1000 * 1000);
}
#Provides
#Singleton
OkHttp3Downloader getOkHttp3Downloader(OkHttpClient okHttpClient) {
return new OkHttp3Downloader(okHttpClient);
}
#Provides
#Singleton
OkHttpClient getOkHttpClient(HttpLoggingInterceptor loggingInterceptor, Cache cache) {
return new OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.cache(cache)
.build();
}
#Provides
#Singleton
Retrofit getRetrofit(OkHttpClient client, GsonConverterFactory gsonConverterFactory, RxJava2CallAdapterFactory callAdapter) {
return new Retrofit.Builder()
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(callAdapter)
.baseUrl("https://api.themoviedb.org/3/")
.client(client)
.build();
}
#Provides
#Singleton
HttpLoggingInterceptor getHttpLoggingInterceptor() {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(message -> Timber.tag("OkHttp").d(message));
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return loggingInterceptor;
}
#Provides
#Singleton
GsonConverterFactory getGsonConverterFactory() {
return GsonConverterFactory.create();
}
#Provides
#Singleton
RxJava2CallAdapterFactory getRxJavaFactory() {
return RxJava2CallAdapterFactory.create();
}
}
And finally the MovieListActivityModule
#Module(includes = NetworkModule.class)
public class MoviesListActivityModule {
#Provides
#Singleton
TmdbService getTmdbService(Retrofit retrofit) {
return retrofit.create(TmdbService.class);
}
#Provides
#Singleton
Picasso getPicasso(#Named("application-context") Context context) {
return new Picasso.Builder(context)
.loggingEnabled(true)
.build();
}
}
And this is the ActivityBuilder class
#Module
public abstract class ActivityBuilder {
#ContributesAndroidInjector(modules = MoviesListActivityModule.class)
abstract MoviesListActivity bindMoviesListActivity();
}
And finally the AppComponent
#Singleton
#Component(modules = {AndroidInjectionModule.class, ContextModule.class, ActivityBuilder.class})
public interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
AppComponent build();
}
void inject(MovieInfoApp app);
}
I am new to Dagger 2 and I followed this from a random tutorial of Medium.
I don't see any SubComponent here. I understand that the subcomponent is generated.
This error just occurs for the #Singleton scoped dependencies.
I followed some stack overflow links and added #Singleton to the AppComponent interface.
How do I fix this?
Rename MoviesListActivityModule to MoviesListApplicationModule, take it off of your #ContributesAndroidInjector, and put it onto your AppComponent's modules list instead.
Behind the scenes, #ContributesAndroidInjector generates a #Subcomponent specific to your MoviesListActivity. When you try to inject your MoviesListActivity using AndroidInjection.inject(Activity), Dagger creates a subcomponent instance that holds MoviesListActivity's MembersInjector (the generated code that knows how to populate all the #Inject fields in your MoviesListActivity) and any scoped bindings that your Activity (or its dependencies) may need. That's the component you're missing, and it's named after the Module and #ContributesAndroidInjector method name, ActivityBuilder_BindMoviesListActivity.MoviesListActivitySubcomponent.
You can add scopes (like an #ActivityScope you create) to #ContributesAndroidInjector, and dagger.android will add them onto the generated subcomponent, just like setting modules = {/*...*/} will add modules onto it. However, that isn't your problem.
First of all, you were right to add #Singleton to your AppComponent; that's a very common thing, and it's right to do here. Adding #Singleton there means that Dagger will automatically watch out for bindings that are marked with #Singleton and keep copies of them in the component you annotate the same way. If you were to create an #ActivityScope annotation and add it to your subcomponent, Dagger would watch out for bindings that were annotated with #ActivityScope and return the same instance from within the same Activity instance but a different instance compared to other instances of the same Activity or other Activity types.
Your problem is that you are adding #Singleton-scoped bindings Picasso and TmdbService into your unscoped subcomponent graph. What you're telling Dagger is that across the lifetime of your application component (not your Activity, your application) you should always return the same Picasso and TmdbService instances. However, by making that binding on the module list of your subcomponent rather than your top-level #Singleton #Component, you tell Dagger about these application-level objects when it's trying to configure activity-level bindings. The same applies to the bindings in your NetworkModule, which are also listed in your error message.
After you move the modules, you will always receive the same instance of Picasso, TmdbService, OkHttpClient, and all of those others—which should allow those objects to help manage caches, batches, and requests in flight without you having to worry about which instance you're interacting with. It'll always be the same instance across the lifetime of your app.

Cannot access Nullable Dagger2 Android

I am writing an app where I am using Dagger2 for dependency Injection. I am new to dagger. I am getting confused on how it works and I am not able to figure it out how to use this library. I have tried writing below modules and components with the help of examples in blogs. I have mentioned the purpose of that module. Please correct me if I am wrong.
App Module and Component : It should generate a singleton instance across the application and I want to use this instance to access some android resources
#Module
public class AppModule {
private BaseApplication baseApplication;
public AppModule(BaseApplication baseApplication){
this.baseApplication = baseApplication;
}
#Provides
#Singleton
BaseApplication providesApplication(){
return baseApplication;
}
}
#Singleton
#Component(modules = {AppModule.class})
public interface AppComponent {
BaseApplication getBaseApplication();
}
Instantiation of AppComponent
public class BaseApplication extends Application {
private AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.builder().appModule(new
AppModule(this)).build();
}
public AppComponent getAppComponent(){
return appComponent;
}
}
The above code works fine. I am getting problems in the below code
Location Module and Component : Is it Ok if I don't have a constructor
for the below module?
#Module
public class LocationModule {
#IntDef(
{LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY,
LocationRequest.PRIORITY_HIGH_ACCURACY,
LocationRequest.PRIORITY_LOW_POWER,
LocationRequest.PRIORITY_NO_POWER})
#Retention(RetentionPolicy.SOURCE)
public #interface LocationPriority {}
#Provides
#Singleton
#Named("default")
LocationRequest providesLocationRequest(){
return new LocationRequest()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(Constants.LOCATION_UPDATE_INTERVAL_MS)
.setFastestInterval(Constants.LOCATION_UPDATE_FASTEST_INTERVAL_MS)
.setSmallestDisplacement(Constants.LOCATION_UPDATE_DISPLACEMENT_METERS);
}
#Provides
#Singleton
#Named("custom")
LocationRequest providesCustomLocationRequest(int interval, int
fastestInterval, #LocationPriority int priority, float updateDisplacement) {
return new LocationRequest()
.setPriority(priority)
.setInterval(interval)
.setFastestInterval(fastestInterval)
.setSmallestDisplacement(updateDisplacement);
}
#Provides
#Singleton
LocationSettingsRequest providesLocationSettingsRequest(LocationRequest
locationRequest){
return new LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest)
.build();
}
#Provides
#Singleton
FusedLocationProviderClient providesFusedLocationClient(BaseApplication
baseApplication){
return LocationServices.getFusedLocationProviderClient(baseApplication);
}
#Provides
#Singleton
SettingsClient providesSettingsClient(BaseApplication baseApplication){
return LocationServices.getSettingsClient(baseApplication);
}
}
#Singleton
#Component(modules = {LocationModule.class, AppModule.class})
public interface LocationComponent {
**Do we Really need a method here?**
void inject(GetLocationUseCase getLocationUseCase);
}
I am getting the following error
error: cannot access Nullable class file for
javax.annotation.Nullable not found
after using #Inject in below class. If I remove #Inject the error goes away.
public final class GetLocationUseCase implements
UseCaseContract.BusinessLogic {
UseCaseContract.Mediator mediator;
#Inject
FusedLocationProviderClient fusedLocationProviderClientl;
#Override
public void onInitialize() {
BaseApplication application = mediator.requestUserContext();
DaggerLocationComponent.builder().appModule(new
AppModule(application)).locationModule(new
LocationModule()).build().inject(this);
}
Why am I getting that error? Any help would be appreciated. Thanks in advance.
You need to add missing modules in your Component ..
For example, you will get this error if you remove NetModule from below
#Component(modules = {AppModule.class, NetModule.class, MainModule.class})
public interface AppComponent {
...
In case someone like me out there. I forgot to add #Provides annotation to the Dagger Module.
In my case I had a class with #Inject annotated constructor which extended another 3rd party class which had #Nullable annotation on one of the method parameters. Once I removed this extension everything started to work normally.
After wasting about 1 day on this issue, I found out that I need to temporarily add findbugs dependency like this:
implementation 'com.google.code.findbugs:jsr305:3.0.2'
Then dagger will print the actual error.

Modules with different Scopes

How do I make a Module which has an annotation, like #UserScope, dependent on another Module that's a #Singleton?
#Module(includes = {ApplicationModule.class})
public class JobManagerModule
{
private static final String TAG = JobManagerModule.class.getSimpleName();
#UserScope
#Provides
public JobManager providesJobManager(final Context context)
{
Log.d(TAG, "Providing JobManager");
final Configuration configuration = new Configuration.Builder(context).build();
return new JobManager(configuration);
}
}
Here, JobManagerModule provides using #UserScope but the ApplicationModule provides the Context object (which JobManagerModule needs) as a #Singleton.
This shows errors.
If you want to create a different Scope, then this scope must be a subcomponent of #Singleton.
Suppose you have ApplicationComponent annotated with #Singleton:
#Singleton
#Component(
modules = ApplicationModule.class
)
public interface ApplicationComponent {
JobManagerComponent provide(JobManagerModule jobManagerModule);
}
ApplicationModule provides Context:
#Module
public class ApplicationModule {
protected final Application mApplication;
public ApplicationModule(Application application) {
mApplication = application;
}
#Provides
#ApplicationContext
public Context provideApplicationContext() {
return mApplication;
}
}
Notice, that ApplicationComponent must provide JobManagerComponent
and Context is provided with #ApplicationContext annotation.
Now you create JobManagerComponent as a #Subcomponent of ApplicationComponent:
#UserScope
#Subcomponent(
modules = JobManagerModule.class
)
public interface JobManagerComponent{
}
JobManagerModule:
#Module
public class JobManagerModule
{
private static final String TAG = JobManagerModule.class.getSimpleName();
#UserScope
#Provides
public JobManager providesJobManager(#ApplicationContext Context context)
{
Log.d(TAG, "Providing JobManager");
final Configuration configuration = new Configuration.Builder(context).build();
return new JobManager(configuration);
}
}
Notice the removal of include from #Module annotation and Context annotated with #ApplicationContext
Creation of JobManagerComponent:
JobManagerComponent jobComponent = DaggerApplicationComponent.builder()
.applicationModule(applicationModule)
.build()
.provide(new JobManagerModule());

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 2 mixed scopes

Previously I had only one AppComponent with four modules (AppModule, NetworkModule, StorageModule, PresentersModule) and injected singletons everywhere. Recently, I decided to make small refactoring in my app and divide it into scopes. I think, presenters can live within activities only, so I created #ActivityScope and ActivityModule, but the project cannot be compiled because of my misunderstanding how to mix these scopes.
I've read a lot of articles and questions at stackoverflow, but everywhere there are simple examples where modules are independent. In my case such thing as
#Singleton
#Component(modules = { AppModule.class, StorageModule.class, NetworkModule.class })
public interface AppComponent {
ActivityComponent plus(PresentersModule module); // <-- error
}
is not working. I get this error:
Error:(19, 1) error: com.my.package.di.component.ActivityComponent scoped with #com.my.package.di.scope.ActivityScope may not reference bindings with different scopes:
#Provides #Singleton android.app.Application com.my.package.di.module.AppModule.provideApplication()
#Provides #Singleton com.my.package.network.FeedBurnerApi com.my.package.di.module.NetworkModule.provideFeedBurnerApi(android.app.Application)
#Provides #Singleton android.database.sqlite.SQLiteOpenHelper com.my.package.di.module.StorageModule.provideSQLiteOpenHelper(android.app.Application)
#Provides #Singleton com.my.package.storage.Repository com.my.package.di.module.StorageModule.provideRepository(android.database.sqlite.SQLiteOpenHelper)
#Provides #Singleton com.my.package.SharedPreferencesHelper com.my.package.di.module.StorageModule.provideSharedPreferencesHelper(android.app.Application)
So, the question is how I can get the instance of my ActivityComponent?
You can see dependencies between modules below:
Application module:
#Module
public final class AppModule {
private final MyApplication mApplication;
public AppModule(MyApplication application) { ... }
#Provides #Singleton Application provideApplication() { ... }
}
Network module:
#Module(includes = { AppModule.class })
public final class NetworkModule {
#Provides #Singleton FeedBurnerApi provideFeedBurnerApi(Application application) { ... }
#Provides #Singleton Retrofit provideRetrofit() { ... }
}
Storage module:
#Module(includes = { AppModule.class })
public final class StorageModule {
#Provides #Singleton Repository provideRepository(SQLiteOpenHelper sqLiteOpenHelper) { ... }
#Provides #Singleton SQLiteOpenHelper provideSQLiteOpenHelper(Application application) { ... }
#Provides #Singleton SharedPreferencesHelper provideSharedPreferencesHelper(Application application) { ... }
}
Presenters module:
#Module(includes = { AppModule.class, NetworkModule.class, StorageModule.class })
public final class PresentersModule {
#Provides FeedPageViewPresenter provideFeedPageViewPresenter(FeedBurnerApi api, Repository repository, SharedPreferencesHelper preferences) { ... }
#Provides #ActivityScope SlidingTabsViewPresenter provideSlidingTabsViewPresenter(Repository repository) { ... }
}
Application component:
#Singleton
#Component(modules = { AppModule.class, StorageModule.class, NetworkModule.class })
public interface AppComponent {}
Activity component:
#Subcomponent(modules = PresentersModule.class)
#ActivityScope
public interface ActivityComponent {
void inject(FeedPageView view);
void inject(SlidingTabsView view);
}
The problem was in my PresentersModule.
Since Subcomponents have access to entire objects graph from their parents, I don't need to include these dependencies in my sub-module.
So, I changed this code:
#Module(includes = { AppModule.class, NetworkModule.class, StorageModule.class })
public final class PresentersModule { ... }
with this:
#Module
public final class PresentersModule { ... }
and it solved my issue.

Categories

Resources