我试图把头放在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中可确保范围图可以自由进行垃圾收集。
编辑
杰西·威尔逊(Jesse Wilson)最近发布了一个小窍门
Dagger 1.0严重破坏了其作用域名称... @Singleton批注用于根图和自定义图,因此要弄清楚事物的实际作用域是非常棘手的。
我已阅读/听到的所有其他内容都指向Dagger 2,以改善示波器的工作方式,但我仍在努力理解差异。根据下面的@Kirill Boyarshinov的评论,像往常一样,组件或依赖项的生命周期仍由具体引用来确定。那么Dagger 1.x和2.0范围之间的区别纯粹是语义上的清楚吗?
我的理解
匕首1.x
依赖关系是否@Singleton
存在。根图和子图中的依赖项也同样如此,从而导致该依赖项绑定到哪个图上的模棱两可(请参阅Dagger中子图内的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的问题。
plus()
对新图的引用对应用程序级ObjectGraph对象进行子图预订时,该对象存储在Activity中,并绑定到其生命周期(在中取消引用onDestroy
)。至于范围,它们确保您的组件实现在编译时生成时没有错误,并且满足每个依赖关系。因此,它不仅用于文档目的。从此线程中查看一些示例。