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;
}
}
하위 범위는 참조를 유지하는 한 존재했으며,이 경우 활동의 수명주기였습니다. onDestroy에서 참조를 삭제하면 범위가 지정된 그래프를 가비지 수집 할 수 있습니다.
편집하다
Jesse Wilson은 최근 mea culpa를 게시했습니다.
Dagger 1.0은 범위 이름을 잘못 정돈했습니다 … @Singleton 주석은 루트 그래프와 사용자 정의 그래프 모두에 사용되므로 사물의 실제 범위가 무엇인지 알아내는 것이 까다 롭습니다.
그리고 내가 읽은 모든 것은 Dagger 2에 대한 요점이 스코프 작동 방식을 개선하지만 그 차이점을 이해하기 위해 고심하고 있습니다. 아래의 @Kirill Boyarshinov의 의견에 따르면 구성 요소의 수명주기 또는 종속성은 평소와 같이 구체적인 참조로 결정됩니다. 그렇다면 Dagger 1.x와 2.0 스코프의 차이점은 순전히 의미 명확성의 문제입니까?
내 이해
단검 1.x
의존성은 어느 쪽이든 아니든간에 요 @Singleton
. 루트 그래프와 하위 그래프의 종속성에 대해서도 동일하게 적용되므로 종속성이 바인딩 된 그래프에 대한 모호함이 발생합니다 ( 단어에서 하위 그래프 내에 단일 톤이 캐시되어 있거나 새 활동 하위 그래프 일 때 항상 다시 작성 됨 참조). 건설 되었습니까? )
단검 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
이제 응용 프로그램 수준의 싱글 톤 인스턴스를위한 것이며 사용자 지정 범위는 수명주기가 짧은 싱글 톤 종속성에 주석을 추가하는 데 선호되는 방법입니다.
개발자는 더 이상 필요하지 않은 참조를 삭제하여 구성 요소 / 종속성의 수명주기를 관리하고 구성 요소가 의도 한 범위 내에서 한 번만 생성되도록해야하지만 사용자 지정 범위 주석을 사용하면 해당 범위를 쉽게 식별 할 수 있습니다. .
$ 64k 질문 *
Dagger 2 범위 및 라이프 사이클에 대한 이해가 정확합니까?
* 실제로 $ 64’000 질문이 아닙니다.
답변
당신의 질문에 관해서는
Dagger 2에서 구성 요소 (객체 그래프)의 수명주기를 결정하는 요소는 무엇입니까?
짧은 대답은 당신이 그것을 결정하는 것 입니다. 구성 요소에는 다음과 같은 범위가 주어질 수 있습니다.
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ApplicationScope {
}
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}
다음 두 가지에 유용합니다.
- 범위의 유효성 검사 : 구성 요소에는 범위가 지정되지 않은 공급자 또는 구성 요소와 범위가 같은 범위의 공급자 만있을 수 있습니다.
.
@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();
}
}
- 범위가 지정된 종속성의 하위 범위를 지정할 수 있으므로 “superscoped”구성 요소에서 제공된 인스턴스를 사용하는 “subscoped”구성 요소를 만들 수 있습니다.
@Subcomponent
주석 또는 구성 요소 종속성 으로 수행 할 수 있습니다 . 나는 개인적으로 의존성을 선호합니다.
@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));
또는 구성 요소 종속성을 사용할 수 있습니다
@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();
알아야 할 중요한 사항 :
-
범위가 지정된 공급자 는 각 구성 요소에 대해 해당 범위 에 대해 하나의 인스턴스를 만듭니다 . 구성 요소는 자체 인스턴스를 추적하지만 다른 구성 요소에는 공유 범위 풀이나 마법이 없습니다. 주어진 범위에서 하나의 인스턴스를 가지려면 하나의 구성 요소 인스턴스가 필요합니다. 그렇기 때문에
ApplicationComponent
자체 범위 종속성에 액세스하려면를 제공해야합니다 . -
구성 요소는 하나의 범위가 지정된 구성 요소 만 범위를 지정할 수 있습니다. 여러 범위의 구성 요소 종속성이 허용되지 않습니다.