Я пытаюсь осмыслить области видимости в 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 гарантирует, что граф с областью видимости свободен для сбора мусора.
ИЗМЕНИТЬ
Джесси Уилсон недавно опубликовал mea culpa
Dagger 1.0 сильно напортачил с именами областей видимости ... Аннотация @Singleton используется как для корневых графов, так и для пользовательских графов, поэтому сложно определить, какова реальная сфера действия объекта.
и все остальное, что я читал / слышал, указывает на то, что Dagger 2 улучшает работу прицелов, но я изо всех сил пытаюсь понять разницу. Согласно комментарию @Kirill Boyarshinov ниже, жизненный цикл компонента или зависимости по-прежнему определяется, как обычно, конкретными ссылками. Так является ли разница между прицелами Dagger 1.x и 2.0 чисто семантической ясностью?
Мое понимание
Кинжал 1.x
Зависимости были либо @Singleton
, либо нет. Это в равной степени относится к зависимостям в корневом графе и подграфах, что приводит к неоднозначности относительно того, к какому графу привязана зависимость (см. В 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;
}
}
Вывод заключается в том, что использование @PerActivity
сообщает о вашем намерении относительно жизненного цикла этого компонента, но в конечном итоге вы можете использовать компонент где угодно и когда угодно. Единственное обещание Dagger состоит в том, что для данного компонента аннотированные методы области видимости будут возвращать единственный экземпляр. Я также предполагаю, что Dagger 2 использует аннотацию области для компонента, чтобы убедиться, что модули предоставляют только зависимости, которые находятся либо в той же области, либо без области действия.
В итоге
Зависимости по-прежнему являются одноэлементными или не-одноэлементными, но @Singleton
теперь предназначен для одноэлементных экземпляров на уровне приложения, и настраиваемые области являются предпочтительным методом аннотирования одноэлементных зависимостей с более коротким жизненным циклом.
Разработчик несет ответственность за управление жизненным циклом компонентов / зависимостей, отбрасывая ссылки, которые больше не нужны, и отвечает за обеспечение того, чтобы компоненты были созданы только один раз в области, для которой они предназначены, но настраиваемые аннотации области облегчают идентификацию этой области. .
Вопрос на $ 64 000 *
Правильно ли я понимаю прицелы и жизненные циклы Dagger 2?
* На самом деле это не вопрос на 64 тысячи долларов.
plus()
ссылки на новый граф сохранялся в Activity и был привязан к его жизненному циклу (разыменовано вonDestroy
). Что касается областей видимости, они гарантируют, что реализации ваших компонентов будут сгенерированы без ошибок во время компиляции, и все зависимости будут удовлетворены. Так что это не только для документации. Посмотрите несколько примеров из этой темы. - person Kirill Boyarshinov   schedule 10.02.2015