Dagger2 Custom Scopes: Как работают пользовательские области (@ActivityScope)?
Я читаю исходный код Dagger2 Component Scopes Test на GitHub, и я видел "настраиваемую область", определенную для действий с именем @ActivityScope
, но Я видел это в других проектах, включая 4-модуль CleanArchitecture, который имеет область @PerActivity
.
Но буквально код для аннотации @ActivityScope
следующий:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Scope;
/**
* Created by joesteele on 2/15/15.
*/
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}
И это "волшебное" использование в модулях:
@Module
public class ActivityModule {
@Provides @ActivityScope Picasso providePicasso(ComponentTest app, OkHttpClient client) {
return new Picasso.Builder(app)
.downloader(new OkHttpDownloader(client))
.listener(new Picasso.Listener() {
@Override public void onImageLoadFailed(Picasso picasso, Uri uri, Exception e) {
Log.e("Picasso", "Failed to load image: " + uri.toString(), e);
}
})
.build();
}
}
Или пример CleanArchitecture:
@Scope
@Retention(RUNTIME)
public @interface PerActivity {}
@PerActivity
@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {
//Exposed to sub-graphs.
Activity activity();
}
@Module
public class ActivityModule {
private final Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
/**
* Expose the activity to dependents in the graph.
*/
@Provides @PerActivity Activity activity() {
return this.activity;
}
}
Я ясно вижу, что это связано с пользовательскими областями JSR-330, но я действительно не понимаю, что именно происходит здесь, чтобы сделать это так, чтобы этот код позволял данному модулю и/или то, что предоставляется данным модулем, чтобы зависеть от фактического жизненного цикла Activity
, и для того, чтобы существовать только один экземпляр, но только если эта активная активность активна.
Документы говорят следующее:
Scope
Dagger 1 only supported a single scope: @Singleton.
Dagger 2 allows users to any well-formed scope annotation.
The Component docs describe the details of
how to properly apply scope to a component.
Он говорит, чтобы посмотреть страницу Компонентные документы, но это дает мне 404. Я также видел this, но...
Могу ли я попросить некоторую помощь в разъяснении, почему магическое создание этой настраиваемой области делает работу Activity-level scopes
без проблем?
(Ответ заключается в том, что подскоп может получать зависимости от своего суперскопа, а подскоп существует до тех пор, пока компонент выполняет. И вам нужно указать области действия в своих модулях, и вам нужно указать зависимости компонентов для подкапа один суперскоп.)
Ответы
Ответ 1
Стоит отметить, что, по-видимому, Dagger2 создает один экземпляр для каждого поставщика в модуле для каждого компонента.
Итак, чтобы получить провайдера с ограниченным охватом в модуле, вам нужно указать область действия для вашего провайдера модулей.
@Module
public class YourModule {
@Provides
@YourScope //one per component
public Something something() { return new SomethingImpl(); }
@Provides //new instance per injection
public Otherthing otherthing() { return new OtherthingImpl(); }
}
@Component
@YourScope
public interface YourComponent {
Something something();
Otherthing otherthing();
void inject(YourThing yourThing);
}
Затем обратитесь к Кириллскому ответу; по сути, "область" сама по себе определяет, что она отличается от другой. Использование зависимостей компонентов (или подкомпонентов) создает подкласс.
@Module
public class SubModule {
@Provides
@SubScope
public ThatThing thatThing() { return new ThatThingImpl(); }
}
@Component(dependencies={YourComponent.class}, modules={SubModule.class})
@SubScope
public interface SubComponent extends YourComponent {
ThatThing thatThing();
void inject(SubThing subThing);
}
Компонент может зависеть только от одного другого компонента с областью.
Ответ 2
На самом деле нет волшебства. Аннотации пользовательской области - это всего лишь аннотации. Они могут иметь любое имя. Аннотации Scope служат инструментом для статического анализа зависимостей, которые предоставляют модули и компоненты. Поэтому использование @ActivityScope
зависимостей в компоненте @ActivityScope
приведет к ошибке компиляции.
Как определить реальный объем - ваша прерогатива. Определите жизненный цикл вашего компонента области видимости, время его создания и время его уничтожения - это ваш объем. Например. @ActivityScope
привязан к жизненному циклу активности и определяется следующим образом:
private ActivityComponent component;
@Override
protected void onCreate(Bundle savedInstanceState) {
component = DaggerActivityComponent.builder().build();
component.inject(this);
}
@Override
protected void onDestroy() {
component = null;
super.onDestroy();
}
Итак, нет никакой магии. Определите свои области применения семантикой их использования.
Вы также можете найти этот ответ и эти примеры.