I am trying to make my app better and code more maintainable using Dagger2
I caught general idea, but still cannot figure out how scopes are managed by Dagger2
I injected dagger into my project (sounds funny).
I created ApplicationComonent
component and it works perfectly in my project.
Here is my code.
@Singleton
@Component(modules = {
ApplicationModule.class,
ThreadingModule.class,
NetworkModule.class,
DatabaseModule.class,
ServiceModule.class,
ParseModule.class,
PreferencesSessionModule.class})
public interface ApplicationComponent {
ActivityComponent activityComponent(ActivityModule activityModule);
void inject(BaseActivity baseActivity);
void inject(MainAppActivity mainAppActivity);
void inject(MyApplication application);
void inject(BaseFragment baseFragment);
void inject(MyService service);
void inject(RegistrationIntentService service);
}
I create my component instance in MyApplication
class like this
private void initializeAndInjectComponent() {
mApplicationComponent =
DaggerApplicationComponent
.builder()
.threadingModule(new ThreadingModule(1))
.applicationModule(new ApplicationModule(this))
.networkModule(new NetworkModule(
MyService.API_SERVER_BASE_URL,
MyService.TIMEOUT))
.build();
mApplicationComponent.inject(this);
}
And I can obtain component in order to inject in in my Activities
MyApplication application = MyApplication.get(this);
application.getApplicationComponent().inject(this);
Everything works perfectly.
To add each method as well as module class is annotated with @Singleton
scope, all modules related to the ApplicationComponent
Now I want to make dependencies better and I have seen a lot of examples with custom scopes like @PerActivity
, @PerFragment
. I have a lot of questions, but about this later.
So I created ActivityComponent
@PerActivity
@Subcomponent(
modules = {
NetworkServiceModule.class,
ActivityModule.class,
PermissionModule.class
})
public interface ActivityComponent {
Activity activity();
void inject(BaseActivity baseActivity);
}
All modules looks like this
@PerActivity
@Module
public class ActivityModule {
private Activity mActivity;
public ActivityModule(Activity activity) {
this.mActivity = activity;
}
@Provides
@PerActivity
Activity provideActivity() {
return this.mActivity;
}
}
I have following dependencies in my BaseActivity
// Dependencies from ApplicationComponent
@Inject
protected ApplicationSettingsManager mApplicationSettingsManager;
@Inject
protected ScheduledThreadPoolExecutor mPoolExecutor;
// Dependencies from ActivityComponent
@Inject
protected SpiceManager mSpiceManager;
@Inject
protected PermissionController mPermissionController;
And in my onCreate()
method I am injecting as following
MyApplication application = MyApplication.get(this);
application.getApplicationComponent().activityComponent(new ActivityModule(this)).inject(this);
Before creating subcomponent ActivityComponent
it was
MyApplication application = MyApplication.get(this);
application.getApplicationComponent().inject(this);
Now I got an error
Error:(34, 10) error: com.octo.android.robospice.SpiceManager cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
BaseActivity.mSpiceManager
[injected field of type: com.octo.android.robospice.SpiceManager mSpiceManager]
I cannot figure out where is problem, what I missed. My questions about scopes in dagger2.
Everything but @Singleton
is ignored by Dagger 2, am I right ?
I don't understand how life of component is managed ? I have only one idea
When you use
@Singleton
annotation dagger is creating object in some static pool that will exist during whole application lifecycle, and will be destroyed when JVM process (dalvik VM,ART) instance will be destroyed.When you use any other annotation is just for you as developer to better maintain code,
@PerActivity
,@PerFragment
is just custom annotation nothing more. And in case you place@PerFragment
component in Application class it will live as long as Application lives. Am I right ?So I understand this like this, if dagger finds
@Singleton
annotation it will add static reference to component when it is created first time and in case of any other annotation it won't hold reference to component.
I would be very grateful for any help with problems described above.
UPDATE
Thank you David Medenjak
for great answer, I got much better understanding of Dagger2
.
I have also just found the problem, as far as I am using separate Activity
component now, I forgot about two lines in ApplicationComponent
and change inejction in my MainActivity
to ActivityComponent
instead of ApplicationComponent
, so for sure it couldn't resolve dependencies from subcomponent.
void inject(BaseActivity baseActivity);
void inject(MainAppActivity mainAppActivity);
Now everything works perfectly, I like Dagger2
and separated architecture.