Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
}
like image 779
dmitriyzaitsev Avatar asked Nov 10 '15 00:11

dmitriyzaitsev


1 Answers

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.

like image 86
dmitriyzaitsev Avatar answered Sep 18 '22 21:09

dmitriyzaitsev