As for your question
What determines the lifecycle of a component (object graph) in Dagger 2?
The short answer is you determine it. Your components can be given a scope, such as
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ApplicationScope {
}
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}
These are useful for you for two things:
- Validation of scope: a component can only have unscoped providers, or scoped providers of the same scope as your component.
.
@Component(modules={ApplicationModule.class})
@ApplicationScope
public interface ApplicationComponent {
Something something();
AnotherThing anotherThing();
void inject(Whatever whatever);
}
@Module
public class ApplicationModule {
@ApplicationScope //application-scoped provider, only one can exist per component
@Provides
public Something something() {
return new Something();
}
@Provides //unscoped, each INJECT call creates a new instance
public AnotherThing anotherThing() {
return new AnotherThing();
}
}
- Allows for sub-scoping your scoped dependencies, thus allowing you to create a “subscoped” component that uses the provided instances from the “superscoped” component.
This can be done with @Subcomponent
annotation, or component dependencies. I personally prefer dependencies.
@Component(modules={ApplicationModule.class})
@ApplicationScope
public interface ApplicationComponent {
Something something();
AnotherThing anotherThing();
void inject(Whatever whatever);
ActivityComponent newActivityComponent(ActivityModule activityModule); //subcomponent factory method
}
@Subcomponent(modules={ActivityModule.class})
@ActivityScope
public interface ActivityComponent {
ThirdThingy thirdThingy();
void inject(SomeActivity someActivity);
}
@Module
public class ActivityModule {
private Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
//...
}
ApplicationComponent applicationComponent = DaggerApplicationComponent.create();
ActivityComponent activityComponent = applicationComponent.newActivityComponent(new ActivityModule(SomeActivity.this));
Or you can use component dependencies like so
@Component(modules={ApplicationModule.class})
@ApplicationScope
public class ApplicationComponent {
Something something();
AnotherThing anotherThing();
void inject(Whatever whatever);
}
@Component(dependencies={ApplicationComponent.class}, modules={ActivityModule.class})
@ActivityScope
public interface ActivityComponent extends ApplicationComponent {
ThirdThingy thirdThingy();
void inject(SomeActivity someActivity);
}
@Module
public class ActivityModule {
private Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
//...
}
ApplicationComponent applicationComponent = DaggerApplicationComponent.create();
ActivityComponent activityComponent = DaggerActivityComponent.builder().activityModule(new ActivityModule(SomeActivity.this)).build();
Important things to know:
-
A scoped provider creates one instance for that given scope for each component. Meaning a component keeps track of its own instances, but other components don’t have a shared scope pool or some magic. To have one instance in a given scope, you need one instance of the component. This is why you must provide the
ApplicationComponent
to access its own scoped dependencies. -
A component can subscope only one scoped component. Multiple scoped component dependencies are not allowed.