最近,看到一些小夥伴想要入門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: 版權歸做者全部,轉載請註明原文連接