最近,看到一些小伙伴想要入门Dagger2,加之最近刚经历了Dagger2的水深火热,在这里针对Dagger2中不一样的注解方式,会生成怎样的代码,结合其生成的不一样代码,来帮助你们作一些深刻的理解。java
首先,Dagger2是一个DI的解决方案,跟以前接触过的Spring相比,它最主要的好处是经过apt插件在编译阶段时,用来生成注入的代码;而Spring是须要在运行时,经过XML或者注解来进行代码注入的。因此,相比来讲,在性能上,Dagger2是优于Spring,但带来的是编译阶段时间的延长。这样的话,每当咱们修改或者添加这些注解代码的时候,就须要咱们从新Build一下(即由apt插件来生成咱们所须要使用的代码),build时间的延长,感受这对Android开发程序员来讲,应该习觉得常了吧。(掩面而泣。。。)android
另外,不得不提的就是apt插件的成熟。apt插件经过生成代码的方式会使得咱们则针对特定规则的代码,经过添加注解,使用apt在编译阶段生成代码,减小咱们的代码书写量。在gayhub上,已经有不少成熟的库,在使用apt来生成代码,像bundler这个库,就是经过封装Intent参数跟界面组件来绑定,这样咱们就可没必要经过getIntent来一个个获取参数。另外还提供了使用saveState
和restoreState
,使得咱们在界面组件异常退出的时候,没必要再使用savedInstance
来进行数据的保存与获取。还有就是支持Parcelable
数据以及自定义数据parser,另做者不禁不喜欢啊。git
根项目添加apt的版本依赖程序员
dependencies { ... classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' ... }
项目中配置apt插件的使用,以及Dagger2的版本github
apply plugin: 'com.neenbedankt.android-apt' dependencies { compile 'com.google.dagger:dagger:2.0.2' compile 'com.google.dagger:dagger-compiler:2.0.2' compile 'org.glassfish:javax.annotation:10.0-b28' }
这里简单提一下它们的主要做用,dagger2两个很重要的东西,不过介绍的文章不少,须要的话,可自行查找一下。服务器
用来为“被注入方“提供其所须要的注入类。当在子Scoped的Component中,也要被注入相同的类的时候,则须要在当前的Component添加相应的返回对应的类的方法。app
用来提供上层所须要的依赖类。这里所带来的好处就是,全部的依赖类都是经过Module来提供出去,当咱们的依赖发生改变时,咱们只须要在这里改变提供一个新的对象类便可,而不影响咱们上层使用的代码。这里,举一个最简单的例子就是,当咱们调用服务器提供的API的时候,咱们为上层提供了一个Repository命名的接口,并对其返回的是调用API的类;这里,当API还未实现,咱们仅仅对其提供一个MockAPI便可,上层的调用者根本不须要关心个人数据提供从哪里来,是否真实。ide
Provider
定义了一个来提供泛型T的方式,是个很简单的接口。性能
public interface Provider<T> { /** * Provides a fully-constructed and injected instance of {@code T}. * * @throws RuntimeException if the injector encounters an error while * providing an instance. For example, if an injectable member on * {@code T} throws an exception, the injector may wrap the exception * and throw it to the caller of {@code get()}. Callers should not try * to handle such exceptions as the behavior may vary across injector * implementations and even different configurations of the same injector. */ T get(); }
而ScopedProvider
在Provider
的基础上,加上了Scoped的概念,主要经过指定类型的Factory来建立出来对应类型的ScopedProvider,在get方法上,主要经过double-checked
来确保获取实例T的惟一性。gradle
/** * A {@link Provider} implementation that memoizes the result of a {@link Factory} instance. * * @author Gregory Kick * @since 2.0 */ public final class ScopedProvider<T> implements Provider<T> { private static final Object UNINITIALIZED = new Object(); private final Factory<T> factory; private volatile Object instance = UNINITIALIZED; private ScopedProvider(Factory<T> factory) { assert factory != null; this.factory = factory; } @SuppressWarnings("unchecked") // cast only happens when result comes from the factory @Override public T get() { // double-check idiom from EJ2: Item 71 Object result = instance; if (result == UNINITIALIZED) { synchronized (this) { result = instance; if (result == UNINITIALIZED) { instance = result = factory.get(); } } } return (T) result; } /** Returns a new scoped provider for the given factory. */ public static <T> Provider<T> create(Factory<T> factory) { if (factory == null) { throw new NullPointerException(); } return new ScopedProvider<T>(factory); } }
Factory
仅仅继承了一个Provider,并是一个空的实现。
public interface Factory<T> extends Provider<T> {}
从类的注释中,能够看出它的主要做用是给类的属性字段,或者方法参数来提供注入,并忽略是否在含有构造器的注入,都会生成MembersInjector
的类。
/** * Injects dependencies into the fields and methods on instances of type {@code T}. Ignores the * presence or absence of an injectable constructor. * * @param <T> type to inject members of * * @author Bob Lee * @author Jesse Wilson * @since 2.0 (since 1.0 without the provision that {@link #injectMembers} cannot accept * {@code null}) */ public interface MembersInjector<T> { /** * Injects dependencies into the fields and methods of {@code instance}. Ignores the presence or * absence of an injectable constructor. * * <p>Whenever the object graph creates an instance, it performs this injection automatically * (after first performing constructor injection), so if you're able to let the object graph * create all your objects for you, you'll never need to use this method. * * @param instance into which members are to be injected * @throws NullPointerException if {@code instance} is {@code null} */ void injectMembers(T instance); }
这里经过列举几种不一样的注入方式,探究其的实现,了解它们的不一样使用场合
这里先看一个简单的类
public class TestData { @Inject public TestData() { } }
经过在构造器上添加@Inject
注解,则会编译生成一个实现了Factory
接口的单例类,用来生成TestData类。生成的代码以下:
@Generated("dagger.internal.codegen.ComponentProcessor") public enum TestData_Factory implements Factory<TestData> { INSTANCE; @Override public TestData get() { return new TestData() } public static Factory<TestData> create() { return INSTANCE; } }
能够看出经过构造器注入的生成的Factory类,是一个经过enum来实现的一个单例工厂类,是否是有个新技能Get。
实现一个Module来提供TestData的依赖,代码以下:
@Module public class TestModule { @Singleton @Provides public TestData provideTestData(){ return new TestData(); } }
再查看一下,经过apt生成以后的代码:
@Generated("dagger.internal.codegen.ComponentProcessor") public final class TestModule_ProvideTestDataFactory implements Factory<TestData> { private final TestModule module; public TestModule_ProvideTestDataFactory(TestModule module) { assert module != null; this.module = module; } @Override public TestData get() { TestData provided = module.provideTestData(); if (provided == null) { throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method"); } return provided; } public static Factory<TestData> create(TestModule module) { return new TestModule_ProvideTestDataFactory(module); } }
能够看出,针对Module注解,dagger2会根据我们定义了Provides
的注解方法,会生成相应以Module为开头的Factory类,而这个Factory会以Module
做为参数,经过调用Module中的代码,来实现注入类的提供。
这里,以咱们经常使用的Activity
为例,毕竟Activity
的使用但是不容许咱们经过构造器来生成一个Activity的,此时就是MembersInjector
的用武之地了。
来看个Activity的代码先。
public class MainActivity extends AppCompatActivity { @Inject TestData mData; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
固然,也可使用方法来进行注入,像下面这样:
@Inject public void setTestData(TestData testData){ }
会生成一个MainActivity_MembersInjector
的类,以下:
@Generated("dagger.internal.codegen.ComponentProcessor") public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> { private final MembersInjector<AppCompatActivity> supertypeInjector; private final Provider<TestData> mDataProvider; public MainActivity_MembersInjector(MembersInjector<AppCompatActivity> supertypeInjector, Provider<TestData> mDataProvider) { assert supertypeInjector != null; this.supertypeInjector = supertypeInjector; assert mDataProvider != null; this.mDataProvider = mDataProvider; } @Override public void injectMembers(MainActivity instance) { if (instance == null) { throw new NullPointerException("Cannot inject members into a null reference"); } supertypeInjector.injectMembers(instance); instance.mData = mDataProvider.get(); } public static MembersInjector<MainActivity> create(MembersInjector<AppCompatActivity> supertypeInjector, Provider<TestData> mDataProvider) { return new MainActivity_MembersInjector(supertypeInjector, mDataProvider); } }
从上方能够看出,MainActivity_MembersInjector
类经过实现MembersInjector
类,经过injectMembers
方法,来给MainActivity
的实例,采用Provider获取实例的方式,来给咱们以前定义的Inject
参数或者属性,来赋值相应的注入类。
另外,咱们看到,在injectMembers
的方法中,也会调用父类的supertypepInjector
的类,来调用父类的参数注入。
上面,咱们提到了Activity所须要的类注入,只能经过方法参数,或者字段属性两个方式,(构造器是行不通的)。其MembersInjector
的类页编写好了,咱们该怎么调用呢?继续上面的例子,咱们来给MainActivity来提供注入方式,神奇的Component就登上舞台了。
@Singleton @Component(modules = { TestModule.class }) public interface ApplicationComponent { void inject(MainActivity mainActivity); }
这里,component通常在使用的时候,都是须要跟Scope相绑定的,否则会报错。看它的生成代码:
@Generated("dagger.internal.codegen.ComponentProcessor") public final class DaggerApplicationComponent implements ApplicationComponent { private Provider<TestData> provideTestDataProvider; private MembersInjector<MainActivity> mainActivityMembersInjector; private DaggerApplicationComponent(Builder builder) { assert builder != null; initialize(builder); } public static Builder builder() { return new Builder(); } public static ApplicationComponent create() { return builder().build(); } private void initialize(final Builder builder) { this.provideTestDataProvider = ScopedProvider.create(TestModule_ProvideTestDataFactory.create(builder.testModule)); this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideTestDataProvider); } @Override public void inject(MainActivity mainActivity) { mainActivityMembersInjector.injectMembers(mainActivity); } public static final class Builder { private TestModule testModule; private Builder() { } public ApplicationComponent build() { if (testModule == null) { this.testModule = new TestModule(); } return new DaggerApplicationComponent(this); } public Builder testModule(TestModule testModule) { if (testModule == null) { throw new NullPointerException("testModule"); } this.testModule = testModule; return this; } } }
咱们定义好的Component
接口,都会生成一个以Dagger开头的一个实现类。在其中,就能够看到它在实现我们定义的void inject(MainActivity activity)
方法,就是经过使用MainActivity_MembersInjector
类,来完成这一步注入的,有木有颇感神奇啊。这就是apt插件的神奇之处,定义好了规则,按照规则来生成代码便可。
这里,紧接着说起一下Scope
的的用法。当咱们为Component
定义了Scope
以后,而且在module
的方法上,添加了Scope
注解,这样Dagger2在Component
中生成相应的Provider
的时候,就会在前面添加ScopedProvider
,来对咱们所须要的Provider
来提供单例模式的访问。具体能够看到的代码就是上面初始化过程当中,生成provideTestDataProvider
的字段。
掌握了上面说起的这些内容,则Dagger2的不一样注入方法,生成怎样的代码,咱们就上手了Dagger2的使用,如果在使用中还遇到问题的话,欢迎加入QQ群:289926871,来进行交流。
PS: 版权归做者全部,转载请注明原文连接