java 什么决定了 Dagger 2 中组件(对象图)的生命周期?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28411352/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What determines the lifecycle of a component (object graph) in Dagger 2?
提问by Enrico
I'm trying to wrap my head around scopes in Dagger 2, specifically the lifecycle of scoped graphs. How do you create a component that will be cleaned up when you leave the scope.
我正在尝试围绕 Dagger 2 中的范围,特别是范围图的生命周期。您如何创建一个在您离开范围时将被清理的组件。
In the case of an Android application, using Dagger 1.x you generally have a root scope at the application level which you'd extend to create a child scope at the activity level.
在 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;
}
}
The child scope existed as long as you kept a reference to it, which in this case was the lifecycle of your Activity. Dropping the reference in onDestroy ensured the scoped graph was free to be garbage collected.
只要您保留对它的引用,子作用域就存在,在这种情况下,它是您的 Activity 的生命周期。删除 onDestroy 中的引用确保范围图可以自由地被垃圾收集。
EDIT
编辑
Jesse Wilson recently posted a mea culpa
杰西·威尔逊(Jesse Wilson)最近发布了一条过错
Dagger 1.0 badly screwed up its scope names ... The @Singleton annotation is used for both root graphs and custom graphs, so it's tricky to figure out what the actual scope of a thing is.
Dagger 1.0 严重搞砸了它的范围名称......@Singleton 注释用于根图和自定义图,因此很难弄清楚事物的实际范围是什么。
and everything else I've read/heard points towards Dagger 2 improving the way scopes work, but I'm struggling to understand the difference. According to @Kirill Boyarshinov's comment below, the lifecycle of a component or dependency is still determined, as usual, by concrete references. So is the difference between Dagger 1.x and 2.0 scopes purely a matter of semantic clarity?
我读过/听到的其他所有内容都指向 Dagger 2 改进了示波器的工作方式,但我很难理解其中的区别。根据@Kirill Boyarshinov 下面的评论,组件或依赖项的生命周期仍然像往常一样由具体引用决定。那么 Dagger 1.x 和 2.0 范围之间的区别纯粹是语义清晰度的问题吗?
My understanding
我的理解
Dagger 1.x
匕首 1.x
Dependencies were either @Singleton
or not. This was equally true of dependencies in the root graph and subgraphs, leading to ambiguity as to which graph the dependency was bound to (see In Dagger are Singletons within the sub-graph cached or will they always be recreated when a new activity sub-graph is constructed?)
依赖关系是@Singleton
或不是。这同样适用于根图和子图中的依赖关系,导致依赖关系绑定到哪个图的歧义(请参阅在 Dagger 中是子图中缓存的单例,或者它们是否总是在新活动子图时重新创建)构造?)
Dagger 2.0
匕首 2.0
Custom scopes allow you to create semantically clear scopes, but are functionally equivalent to applying @Singleton
in Dagger 1.x.
自定义范围允许您创建语义清晰的范围,但在功能上等同于@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;
}
}
The takeaway being that using @PerActivity
communicates your intentionregarding the lifecycle of this component, but ultimately you can use the component anywhere/anytime. Dagger's only promise is that, for a given component, scope annotated methods will return a single instance. I also assume Dagger 2 uses the scope annotation on the component to verify that modules only provide dependencies that are either in the same scope or non-scoped.
结论是 using@PerActivity
传达了您对该组件生命周期的意图,但最终您可以随时随地使用该组件。Dagger 唯一的承诺是,对于给定的组件,范围注释的方法将返回单个实例。我还假设 Dagger 2 使用组件上的范围注释来验证模块是否仅提供相同范围内或非范围内的依赖项。
In Summary
总之
Dependencies are still either singleton or non-singleton, but @Singleton
is now intended for application-level singleton instances and custom scopes are the preferred method for annotating singleton dependencies with a shorter lifecycle.
依赖项仍然是单例或非单例,但@Singleton
现在用于应用程序级单例实例,自定义范围是注释具有较短生命周期的单例依赖项的首选方法。
The developer is responsible for managing the lifecycle of components/dependencies by dropping references that are no longer needed and responsible for ensuring that components are only created once in the scope for which they are intended, but custom scope annotations make it easier to identify that scope.
开发人员负责通过删除不再需要的引用来管理组件/依赖项的生命周期,并负责确保组件仅在其预期范围内创建一次,但自定义范围注释可以更轻松地识别该范围.
The $64k Question*
6.4 万美元的问题*
Is my understanding of Dagger 2 scopes and lifecycles correct?
我对 Dagger 2 范围和生命周期的理解是否正确?
* Not actually a $64'000 question.
* 实际上不是 64,000 美元的问题。
采纳答案by EpicPandaForce
As for your question
至于你的问题
What determines the lifecycle of a component (object graph) in Dagger 2?
什么决定了 Dagger 2 中组件(对象图)的生命周期?
The short answer is you determine it. Your components can be given a scope, such as
简短的回答是你决定它。您的组件可以被赋予一个范围,例如
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ApplicationScope {
}
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}
These are useful for you for two things:
这些对你有用,有两件事:
- Validation of scope: a component can only have unscoped providers, or scoped providers of the same scope as your component.
- 作用域验证:一个组件只能有无作用域的提供者,或者与您的组件具有相同作用域的有作用域的提供者。
.
.
@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();
}
}
- Allows for sub-scoping your scoped dependencies, thus allowing you to create a "subscoped" component that uses the provided instances from the "superscoped" component.
- 允许对作用域依赖项进行子作用域划分,从而允许您创建一个“子作用域”组件,该组件使用“超作用域”组件中提供的实例。
This can be done with @Subcomponent
annotation, or component dependencies. I personally prefer dependencies.
这可以通过@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));
Or you can use component dependencies like so
或者您可以像这样使用组件依赖项
@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();
Important things to know:
需要了解的重要事项:
A scoped provider creates one instance for that given scope for each component. Meaning a component keeps track of its own instances, but other components don't have a shared scope pool or some magic. To have one instance in a given scope, you need one instance of the component. This is why you must provide the
ApplicationComponent
to access its own scoped dependencies.A component can subscope only one scoped component. Multiple scoped component dependencies are not allowed.
作用域提供者为每个组件的给定作用域创建一个实例。这意味着一个组件会跟踪它自己的实例,但其他组件没有共享范围池或一些魔法。要在给定范围内拥有一个实例,您需要该组件的一个实例。这就是为什么您必须提供
ApplicationComponent
访问其自己的作用域依赖项的原因。一个组件只能对一个作用域组件进行子作用域。不允许多作用域组件依赖项。