什么决定了Dagger 2中组件(对象图)的生命周期?

我试图在Dagger 2的范围内包围我的头,特别是范围图的生命周期。 你如何创build一个组件,当你离开示波器时将被清理。

对于Android应用程序,使用Dagger 1.x,通常在应用程序级别有一个根作用域,您可以在活动级别创build一个子作用域。

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)最近发布了一篇文章

匕首1.0严重搞砸了它的作用域名称@Singleton注释既用于根图也用于自定义graphics,所以很难弄清楚事物的实际范围是什么。

而我读过/听过的所有内容都指向了Dagger 2,改善了示波器的工作方式,但是我正在努力去理解它们之间的差异。 根据下面的@Kirill Boyarshinov的评论,组件或依赖的生命周期仍然像往常一样通过具体的参考来确定。 那么Dagger 1.x和2.0范围的区别纯粹是语义清晰的问题吗?

我的理解

匕首1.x

依赖关系是@Singleton或不。 这同样适用于根图和子图中的依赖关系,从而导致依赖关系绑定到哪个图的模糊性(请参见在Dagger中是在被caching的子图内的单例,或者当新的活动子图时总是被重新创build被构造? )

匕首2.0

自定义作用域允许您创build语义清晰的作用域,但在function上等同于在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是使用@PerActivity传达你关于这个组件生命周期的意图 ,但最终你可以随时随地使用组件。 Dagger唯一的承诺是,对于给定的组件,范围注释方法将返回一个实例。 我还假设Dagger 2使用组件上的作用域注释来validation模块只提供在相同作用域或非作用域中的依赖关系。

综上所述

依赖关系仍然是单身或非单身,但@Singleton现在是为应用程序级别的单例实例,而自定义范围是注释单身人士依赖关系较短生命周期的首选方法。

开发人员负责pipe理组件/依赖关系的生命周期,方法是删除不再需要的引用,并负责确保组件只在预期的作用域中创build一次,但是自定义作用域标注可以更容易地标识该作用域。

$ 64k问题*

我对Dagger 2范围和生命周期的理解是否正确?

*实际上并不是64000美元的问题。

至于你的问题

什么决定了Dagger 2中组件(对象图)的生命周期?

简短的答案是你确定它 。 你的组件可以被赋予一个范围,比如

 @Scope @Retention(RetentionPolicy.RUNTIME) public @interface ApplicationScope { } @Scope @Retention(RetentionPolicy.RUNTIME) public @interface ActivityScope { } 

这两个东西对你有用:

  • 作用域的validation:一个组件只能拥有无与伦比的提供者,或者与你的组件具有相同作用域的作用域提供者。

 @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(); } } 
  • 允许对作用域依赖关系进行子范围划分,从而允许您创build使用“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(); 

重要的事情要知道:

  • 范围提供者为每个组件创build一个给定范围的实例。 意思是一个组件跟踪自己的实例,但其他组件没有共享的作用域池或一些魔法。 要在给定范围内有一个实例,您需要组件的一个实例。 这就是为什么你必须提供ApplicationComponent来访问它自己的作用域依赖关系。

  • 一个组件可以只包含一个范围内的组件。 不允许有多个作用域的组件依赖关系。