I have Singleton scoped module that provides some standard singletons: Application, DB services, etc. But for Activity I have separate module that should create Presenter for he Activity and I need to pass Application context to it. However I get following error when trying to compile the project:
Error:(13, 1) error: xxx.SplashComponent scoped with @xxx.ViewScope may not reference bindings with different scopes:
@Provides @Singleton xxx.ApplicationModule.provideAppContext()
Here is snippet of my Application module:
@Singleton
@Module
public class ApplicationModule {
private Application app;
public ApplicationModule(Application app) {
this.app = app;
}
@Provides
@Singleton
@Named("ui")
Scheduler provideUIScheduler() {
return AndroidSchedulers.mainThread();
}
@Provides
@Singleton
@Named("io")
Scheduler provideIOScheduler() {
return Schedulers.io();
}
@Provides
@Singleton
Application provideApplication() {
return app;
}
@Provides
@Singleton
Context provideAppContext() {
return app;
}
}
And here is Activity module and Component:
@Module
public class SplashModule {
private final FragmentManager fragmentManager;
public SplashModule(FragmentManager fragmentManager) {
this.fragmentManager = fragmentManager;
}
@Provides
@ViewScope
Presenter getPresenter(Context context) {
return new SplashPresenter(context, fragmentManager);
}
}
Component:
@ViewScope
@Component(modules = {SplashModule.class, ApplicationModule.class})
public interface SplashComponent {
void inject(SplashActivity activity);
}
What am I doing wrong?
I want to explain some key points of Dagger 2 from my understanding.
Main actors:
"Component" is the bridge between modules and places where injection happens.
"Module" is the place where we declare our objects which will be injected.
"Scope" is like the life-time of related injection story.
How does it work?
void inject(BaseFragment baseFragment);
*******Expose the provided objects in the component's module to sub components****
DbHelper dbHelper();
Ex:
@Singleton
@Component(modules = { ApplicationModule.class, NetworkModule.class })
public interface ApplicationComponent {
void inject(BaseActivity baseActivity);
DbHelper dbHelper();
}
@PerService @Component(dependencies = ApplicationComponent.class, modules = ServiceModule.class)
public interface ServiceComponent {
void inject(SyncService service);
}
// SyncService.java
@Inject DbHelper dbHelper; (even Singleton scoped)
private void setupInjector() {
ServiceComponent mServiceComponent = DaggerServiceComponent.builder()
.applicationComponent(getApplicationComponent())
.serviceModule(new ServiceModule(this))
.build();
mServiceComponent.inject(this);
}
ok then...
You can inject both unscoped and (Singleton and PerService) scoped objects to your SyncService.class
What am I doing wrong?
This:
@ViewScope
@Component(modules = {SplashModule.class /*View scoped*/,
ApplicationModule.class/*Singleton scoped*/})
You can only include unscoped or modules scoped with the same scope in your components. You will need to use more than one component.
To include the dependencies from your application, you need to have them in a different component, e.g. ApplicationComponent
. If yo do this, you have 2 options: either declare SplashComponent
as a SubComponent
of ApplicationComponent
or add ApplicationComponent
as a dependency to your component. If you add it as a dependency, be sure to also provide methods in your ApplicationComponent
, so that it can access the dependencies.
e.g. if you were to use component dependencies:
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void inject(MyApplication app);
// todo: also add getters for your other dependencies you need further down the graph
Application getApplication();
}
@Component(modules = {SplashModule.class}, dependencies={ApplicationComponent.class})
public interface SplashComponent {
// as before
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With