我试图围绕 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
不是。这同样适用于根图和子图中的依赖关系,导致依赖关系绑定到哪个图的歧义(请参阅在 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
现在适用于应用程序级单例实例,而自定义范围是使用较短生命周期注释单例依赖项的首选方法。
开发人员负责通过删除不再需要的引用来管理组件/依赖项的生命周期,并负责确保组件仅在其预期范围内创建一次,但自定义范围注释更容易识别该范围.
6.4 万美元的问题*
我对 Dagger 2 范围和生命周期的理解是否正确?
* 实际上不是一个 64,000 美元的问题。