Reputation: 4346
I'm using Dagger 2 with simple MVP pattern. I have a @PerApp
and @PerActivity
scopes. I'm injecting presenters dependencies using constructor injection, which makes those presenters "injectable" (I don't need to write provides methods in activity module). Code fragments:
PerApp:
// AppComponent
@PerApp
@Component(modules = {AppModule.class, DataModule.class, NetworkModule.class})
public interface AppComponent {
LoginComponent plus(LoginModule loginModule);
MainComponent plus(MainModule mainModule);
}
// Example @PerApp module
@Module
public class NetworkModule {
@Provides
@PerApp
Retrofit providesRetrofit(){
...
}
}
PerActivity:
// LoginModule
@Module
public class LoginModule {
private final LoginActivity mLoginActivity;
public LoginModule(LoginActivity loginActivity) {
mLoginActivity = loginActivity;
}
@Provides
@PerActivity
Context providesContext() {
return mLoginActivity;
}
}
// LoginComponent
@PerActivity
@Subcomponent(
modules = LoginModule.class
)
public interface LoginComponent {
void inject(LoginActivity loginActivity);
}
Activity:
public class LoginActivity {
@Inject LoginPresenter mPresenter;
}
Presenter:
public class LoginPresenter {
@Inject
public LoginPresenter(Retrofit retrofit) {
...
}
}
It's working great. My question is: What will be the scope of provided LoginPresenter
? Is it gonna be the same as LoginActivity
? Should I annotate the presenter's constructor with @PerActivity
or something?
Upvotes: 11
Views: 2882
Reputation: 2427
It seems the way to specify the scope when having a constructor with an @Inject
annotation is to annotate the class with a scope:
@PerActivity
public class LoginPresenter {
@Inject
public LoginPresenter(Retrofit retrofit) {
...
}
}
I assume LoginPresenter
gets injected only in LoginActivity
, which means Dagger will provide it only once and create a single instance of it. If you injected it multiple times, without the scope annotation you would get different instances.
Upvotes: 3
Reputation: 4346
I've ran some tests to check by myself how exactly scoping works with constructor injection and here are my results.
LoginPresenter
into LoginActivity
:LoginComponent
- @PerActivity
scope (code is exactly the same as in my first post).
I've tried to inject presenter into 2 variables:
public class LoginActivity {
@Inject LoginPresenter A;
@Inject LoginPresenter B;
}
LoginPresenter
annotated with:
A
and B
are differentA
and B
are the sameA
and B
are the sameLoginPresenter
into LoginActivity
and MainActivity
:LoginComponent
, MainComponent
- @PerActivity
scope (code is exactly the same as in my first post).
I've tried to inject presenter into 2 different activities:
public class LoginActivity {
@Inject LoginPresenter A;
}
public class MainActivity {
@Inject LoginPresenter B;
}
LoginPresenter
annotated with:
A
and B
are differentA
and B
are differentA
and B
are the sameUpvotes: 6
Reputation: 31438
It all depends on the component you're using for injection.
Let's assume:
LoginActivity
:@PerActivity
@Component(dependencies = ApplicationComponent.class, modules = LoginActivityModule.class)
public interface LoginActivityComponent {
void inject(LoginActivity loginActivity);
}
ApplicationComponent
for providing objects from @PerApp
scopeIf you don't specify the way a particular module
should provide a particular object (LoginPresenter
for example), you're basically saying to your component
:
I need a
LoginPresenter
instance. I don't care who creates that. Just figure that out yourself.
This component checks if any of the dependent components
/modules
knows how to create that. If not, the asked component
needs to create that itself (with some help from the dependent dagger elements).
An injecting component
can only try to reference ("create") objects that are from the same scope. So if the LoginActivityComponent
is from @PerActivity
, it can create object that are only from this scope.
If you don't specify the scope in your LoginPresenter
, dagger will assume the same scope as the injecting component. If you specify explicitly @PerActivity
scope, it will match the component
scope and everything will be ok. But if you specify a different scope (e.g.@PerApp
), your app won't build correctly since no class from the @PerApp
is providing the way of creating LoginPresenter
.
Disclamer: There might be few parts of my explanation that I have been simplified, so it's a bit easier to understand (mostly in terms of who exactly does what). I tried not to make any simplifications that contradict the logic of the Dagger2 itself.
Upvotes: 3