Я пытаюсь осмыслить области видимости в Dagger 2, в частности, жизненный цикл графиков с областью видимости. Как создать компонент, который будет очищен при выходе из области видимости.
В случае приложения Android при использовании Dagger 1.x у вас обычно есть корневая область видимости на уровне приложения, которую вы расширяете для создания дочерней области на уровне активности.
public class MyActivity {
private ObjectGraph mGraph;
public void onCreate() {
mGraph = ((MyApp) getApplicationContext())
.getObjectGraph()
.plus(new ActivityModule())
.inject(this);
}
public void onDestroy() {
mGraph = null;
}
}
Дочерняя область существует до тех пор, пока вы сохраняете на нее ссылку, которая в данном случае была жизненным циклом вашей Activity. Удаление ссылки в onDestroy гарантирует, что граф с областью видимости свободен для сборки мусора.
РЕДАКТИРОВАТЬ
Джесси Уилсон недавно опубликовал мою ошибку
Dagger 1.0 сильно напортачил с именами своих областей видимости ... Аннотация @Singleton используется как для корневых графов, так и для пользовательских графов, поэтому сложно определить, какова реальная область действия объекта.
и все остальное, что я читал / слышал, указывает на то, что Dagger 2 улучшает работу прицелов, но я изо всех сил пытаюсь понять разницу. Согласно комментарию @Kirill Boyarshinov ниже, жизненный цикл компонента или зависимости по-прежнему определяется, как обычно, конкретными ссылками. Так является ли разница между прицелами Dagger 1.x и 2.0 исключительно вопросом семантической ясности?
Мое понимание
Кинжал 1.x
Зависимости были @Singleton
или нет. Это в равной степени относится к зависимостям в корневом графе и подграфах, что приводит к неоднозначности относительно того, к какому графу была привязана зависимость (см. In Dagger - это синглтоны внутри подграфа, кэшируемые или они всегда будут воссозданы при создании нового подграфа активности построен? )
Кинжал 2.0
Пользовательские области видимости позволяют создавать семантически чистые области действия, но функционально эквивалентны применению @Singleton
в Dagger 1.x.
// Application level
@Singleton
@Component( modules = MyAppModule.class )
public interface MyAppComponent {
void inject(Application app);
}
@Module
public class MyAppModule {
@Singleton @Named("SingletonScope") @Provides
StringBuilder provideStringBuilderSingletonScope() {
return new StringBuilder("App");
}
}
// Our custom scope
@Scope public @interface PerActivity {}
// Activity level
@PerActivty
@Component(
dependencies = MyAppComponent.class,
modules = MyActivityModule.class
)
public interface MyActivityComponent {
void inject(Activity activity);
}
@Module
public class MyActivityModule {
@PerActivity @Named("ActivityScope") @Provides
StringBuilder provideStringBuilderActivityScope() {
return new StringBuilder("Activity");
}
@Name("Unscoped") @Provides
StringBuilder provideStringBuilderUnscoped() {
return new StringBuilder("Unscoped");
}
}
// Finally, a sample Activity which gets injected
public class MyActivity {
private MyActivityComponent component;
@Inject @Named("AppScope")
StringBuilder appScope
@Inject @Named("ActivityScope")
StringBuilder activityScope1
@Inject @Named("ActivityScope")
StringBuilder activityScope2
@Inject @Named("Unscoped")
StringBuilder unscoped1
@Inject @Named("Unscoped")
StringBuilder unscoped2
public void onCreate() {
component = Dagger_MyActivityComponent.builder()
.myApplicationComponent(App.getComponent())
.build()
.inject(this);
appScope.append(" > Activity")
appScope.build() // output matches "App (> Activity)+"
activityScope1.append("123")
activityScope1.build() // output: "Activity123"
activityScope2.append("456")
activityScope1.build() // output: "Activity123456"
unscoped1.append("123")
unscoped1.build() // output: "Unscoped123"
unscoped2.append("456")
unscoped2.build() // output: "Unscoped456"
}
public void onDestroy() {
component = null;
}
}
Вывод заключается в том, что using @PerActivity
сообщает о вашем намерении относительно жизненного цикла этого компонента, но в конечном итоге вы можете использовать компонент где угодно / в любое время. Единственное обещание Dagger состоит в том, что для данного компонента аннотированные методы области видимости вернут единственный экземпляр. Я также предполагаю, что Dagger 2 использует аннотацию области для компонента, чтобы убедиться, что модули предоставляют только зависимости, которые либо находятся в той же области, либо не имеют области.
В итоге
Зависимости по-прежнему являются одноэлементными или не-одноэлементными, но @Singleton
теперь предназначены для одноэлементных экземпляров на уровне приложения, а настраиваемые области являются предпочтительным методом для аннотирования одноэлементных зависимостей с более коротким жизненным циклом.
Разработчик несет ответственность за управление жизненным циклом компонентов / зависимостей, отбрасывая ссылки, которые больше не нужны, и отвечает за обеспечение того, чтобы компоненты были созданы только один раз в области, для которой они предназначены, но настраиваемые аннотации области облегчают идентификацию этой области ,
Вопрос на $ 64 000 *
Правильно ли я понимаю объемы и жизненные циклы Dagger 2?
* На самом деле это не вопрос на 64 тысячи долларов.
plus()
ссылки на новый граф сохранялся в Activity и был привязан к его жизненному циклу (разыменован вonDestroy
). Что касается областей видимости, они гарантируют, что реализации ваших компонентов будут сгенерированы без ошибок во время компиляции, и все зависимости будут удовлетворены. Так что это не только для документации. Посмотрите несколько примеров из этой ветки .