我试图围绕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中的引用可确保范围图可以自由地进行垃圾回收 .
EDIT
杰西威尔逊最近发布了mea culpa
Dagger 1.0严重搞砸了它的范围名称...... @Singleton注释用于根图和自定义图形,因此弄清楚事物的实际范围是很棘手的 .
我读过/听过的所有其他内容都指向Dagger 2改进了范围的工作方式,但我很难理解其中的差异 . 根据@Kirill Boyarshinov在下面的评论,组件或依赖关系的生命周期仍然像往常一样通过具体的引用来确定 . 那么Dagger 1.x和2.0范围之间的差异纯粹是语义清晰度的问题吗?
我的理解
Dagger 1.x
依赖性是 @Singleton
或不是 . 对于根图和子图中的依赖关系同样如此,导致依赖关系绑定到哪个图表的模糊性(参见In Dagger are Singletons within the sub-graph cached or will they always be recreated when a new activity sub-graph is constructed?)
Dagger 2.0
自定义作用域允许您创建语义清晰的作用域,但在功能上等同于在Dagger 1.x中应用 @Singleton
.
// 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美元的问题 .
1 回答
至于你的问题
简短的回答是 you determine it . 您的组件可以被赋予范围,例如
这些对你有用两件事:
.
这可以使用
@Subcomponent
注释或组件依赖性来完成 . 我个人更喜欢依赖 .或者你可以像这样使用组件依赖
重要的事情要知道:
作用域提供程序为该给定作用域 for each component 创建一个实例 . 意味着组件跟踪其自己的实例,但其他组件没有共享范围池或某些魔术 . 要在给定范围内拥有一个实例,您需要一个组件实例 . 这就是您必须提供
ApplicationComponent
来访问其自己的作用域依赖项的原因 .组件只能包含一个范围组件 . 不允许多个范围的组件依赖项 .