Dagger2 Custom Scopes : How do custom-scopes (@ActivityScope) actually work?

Actually there is no magic. Custom scope annotations are just annotations. They can have any name.

First function of scopes is a way to tell Dagger compiler which scopes are allowed within scoped component. That’s why using @ActivityScope dependency in non-@ActivityScope component will fire a compilation error.

In fact components can declare many scopes (e.g. @ActivityScope and @UiScope) and Dagger will treat both of them as single scope – it’s called scope aliasing. For example, it’s useful in multi module projects – when one Gradle module defines one scope with its Dagger modules and another Gradle module defines another scope, while both of them can be used as single aliased scope in some third Gradle module that defines Dagger component.

Second function is to limit number of instances allowed within scoped component. There are several types of scopes supported:

Unscoped – when no annotation declared. Unscoped dependency will have simple Provider generated without any caching and any instance of that dependency created in component will be new for every new injection (as in constructor, or in module provision method, or just as a field).

Custom scope e.g. @ActivityScope annotation defined with @javax.inject.Scope annotation – Dependencies declared with that scope with have caching Provider with double-check lock generated and only single instance will be created for it within component declared with the same scope and its creation will be thread safe. Note that for every instance of component itself new instance of that dependency will be created.

Reusable scope – declared with @dagger.Reusable annotation – Dependencies declared with that scope may be shared between different components through common parent component and will have caching Provider with single-check lock generated. It is useful when dependency does not necessarily need to have single instance but may be shared for increased performance (less allocations) in single component or between components.

For more info on how scopes work refer to user’s guide and Dagger’s generated code.

How to define the actual scope is your prerogative. Define the livecycle of your scope component, when it’s created and when it destroyed – this is your scope. E.g. @ActivityScope is tied to Activity livecycle and defined like that:

private ActivityComponent component;

@Override
protected void onCreate(Bundle savedInstanceState) {
    component = DaggerActivityComponent.builder().build();
    component.inject(this);
}

@Override
protected void onDestroy() {
    component = null;
    super.onDestroy();
}

So there is no magic. Define your scopes by the semantics of using them.
You may also find useful this answer and these examples.

EDIT 14.10.2018 Expanded on scopes functions and types to eliminate ambiguity in previous answer.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)