上一篇文章介绍了Dagger2的基本用法,这篇文章主要说一下Dagger2中@Scope和@Subcomponent这两个注解的用法和原理。
上一篇文章中提到:
如上面例子所示,如果要求D对象为单例,可以通过@Singleton注解来实现。首先我们需要在依赖图中声明对象是单例的:
@Module
public class DModule {
@Provides
@Singleton
public D provideD() {
return new D();
}
}
DComponent接口也需要声明:
@Singleton @Component(modules = DModule.class) public interface DComponent { D provideD(); }
如此,当我们注入D对象时,可保证每次注入的是同一个D对象:
DComponentdComponent = DaggerDComponent.create(); D d1 = dComponent.provideD(); D d2 = dComponent.provideD(); // d1 == d2
在我们看来,只是多加了一个注解而已,便实现了单例模式。要知道其原理,要从Dagger2生成的源码入手。
以如下例子为例:
public class A { public A(){ } } public class B { A a; public B(A a) { this.a = a; } } public class C { A a; B b; public C(A a, B b) { this.a = a; this.b = b; } }
@Module public class ABCModule { @Provides public A provideA() { return new A(); } @Provides public B provideB(A a) { return new B(a); } @Provides public C provideC(A a, B b) { return new C(a, b); } }
@Component(module=ABCModule.class) public interface ABCComponent { public A provideA(); public B provideB(); public C provideC(); void inject(Mainmain); }
public class Main { @Inject C c; public Main() { ABCComponentabcComponent = DaggerABCComponent .builder() .dComponent(dComponent) .build(); A a = abcComponent.provideA(); B b = abcComponent.provideB(); abcComponent.inject(this); } }
编译工程,Dagger2在项目路径下生成了如下文件:
[dagger2] ┣━[di] ┃ ┣━[component] ┃ ┃ ┗━DaggerABCComponent.java ┃ ┗━[module] ┃ ┣━ABCModule_ProvideAFactory.java ┃ ┣━ABCModule_ProvideBFactory.java ┃ ┗━ABCModule_ProvideCFactory.java ┗━[model] ┗━Main_MembersInjector.java
(利用 这个工具 生成了文件结构图)
注意,生成的文件在关联的类相同路径下。如DaggerABCComponent类生成在ABCComponent路径下。
我们先来看看实际接触到的DaggerABCComponent类:
@Generated("dagger.internal.codegen.ComponentProcessor") public final class DaggerABCComponent implements ABCComponent { private Provider<A> provideAProvider; private Provider<B> provideBProvider; private Provider<C> provideCProvider; private MembersInjector<Main> mainMembersInjector; private DaggerABCComponent(Builderbuilder) { assert builder != null; initialize(builder); } public static Builderbuilder() { return new Builder(); } public static ABCComponentcreate() { return builder().build(); } private void initialize(final Builderbuilder) { this.provideAProvider = ABCModule_ProvideAFactory.create(builder.aBCModule); this.provideBProvider = ABCModule_ProvideBFactory.create(builder.aBCModule, provideAProvider); this.provideCProvider = ABCModule_ProvideCFactory.create(builder.aBCModule, provideAProvider, provideBProvider); this.mainMembersInjector = Main_MembersInjector.create(provideCProvider); } @Override public A provideA() { return provideAProvider.get(); } @Override public B provideB() { return provideBProvider.get(); } @Override public C provideC() { return provideCProvider.get(); } @Override public void inject(Mainmain) { mainMembersInjector.injectMembers(main); } public static final class Builder { private ABCModuleaBCModule; private Builder() { } public ABCComponentbuild() { if (aBCModule == null) { this.aBCModule = new ABCModule(); } return new DaggerABCComponent(this); } public BuilderaBCModule(ABCModuleaBCModule) { if (aBCModule == null) { throw new NullPointerException("aBCModule"); } this.aBCModule = aBCModule; return this; } } }
来看几个关键点:
DaggerABCComponent需要Builder来进行初始化。Builder的作用是提供对象的module。
对象通过Provider从依赖图中取出。Provider由Factory生成时会有类似依赖注入的操作。
通过MembersInjector进行依赖注入。
这几个关键类的关系可用下图表示:
+---------------------------------------+ | DaggerABCComponent | | | | +----------+ create +-----------+------------+ | | Factory +-----+-----> | Provider<A> | | +----+-----+ | +----+------+------------+ | ^ | | | | | | | | +--v------+------------+ | | +-----> | |Provider<B> | | | ABCModule | | +--+------+------------+ | | | | | | | | | +----v------+------------+ | +----+----+ +-----> | Provider<C> | | | Builder | +-----------+------------+ | +---------+ | | | | +--------------------+ +-----------+------------+ | |Main_MembersInjector+--> | MembersInjector<Main> | | +--------------------+ +-----------+------------+ | | +---------------------------------------+
其中最最关键的是Factory和Provider。以B类为例,从依赖图中取出B对象,需要经过如下代码:
... this.provideBProvider = ABCModule_ProvideBFactory.create(builder.aBCModule, provideAProvider); ... @Override public B provideB() { return provideBProvider.get(); }
ABCModule_ProvideBFactory的源码如下所示:
@Generated("dagger.internal.codegen.ComponentProcessor") public final class ABCModule_ProvideBFactory implements Factory<B> { private final ABCModulemodule; private final Provider<A> aProvider; public ABCModule_ProvideBFactory(ABCModulemodule, Provider<A> aProvider) { // 根据之前的依赖关系,注入ProviderA assert module != null; this.module = module; assert aProvider != null; this.aProvider = aProvider; } @Override public B get() { B provided = module.provideB(aProvider.get()); // 从ProviderA中取出A对象,再生成B对象 if (provided == null) { throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method"); } return provided; } public static Factory<B> create(ABCModulemodule, Provider<A> aProvider) { return new ABCModule_ProvideBFactory(module, aProvider); } }
Factory和Provider接口如下所示:
public interface Factory<T> extends Provider<T> { } public interface Provider<T> { T get(); }
从使用者的角度看,无需关心对象是如何生成的,只需调用provider的get方法即可获得对象。而且这时的对象应该是符合既定的规则并且初始化好可以马上用的。
从ABCModule_ProvideBFactory(或者某个Provider)的角度看,在初始化方法里就明确了自己所需依赖的对象(这里是ProviderA)。在get方法的实现里,只需关心B对象的生成。当需要A对象时,直接从外部“注入”的providerA取出即可。
再来看一看Main_MembersInjector的实现:
@Generated("dagger.internal.codegen.ComponentProcessor") public final class Main_MembersInjector implements MembersInjector<Main> { private final Provider<C> cProvider; public Main_MembersInjector(Provider<C> cProvider) { assert cProvider != null; this.cProvider = cProvider; } @Override public void injectMembers(Maininstance) { if (instance == null) { throw new NullPointerException("Cannot inject members into a null reference"); } instance.c = cProvider.get(); } public static MembersInjector<Main> create(Provider<C> cProvider) { return new Main_MembersInjector(cProvider); } }