標籤:
本篇文章已授權公眾號 guolin_blog (郭霖)獨家發布
MVP模式講解
在MVP中使用Dagger2
Dagger2的注入原理解析
在上篇部落格中我們介紹了Dagger2該如何在項目中使用,這篇部落格將繼續分析Dagger2實現的原理,代碼依然採用上篇的代碼,看這裡。
Dagger2的注入原理
原理的講解我們通過小明來帶我們學習。
小明在看了MVP的實戰解析和Dagger2的使用後知道了Dagger2該如何在MVP模式中使用,但是小明是一個要求上進的好同學,小明並不滿足於如何使用,小明想鑽研鑽研源碼,看看如何?的。
小明在鑽研Dagger2的時候突然意識到Dagger2是採用註解的形式完成任務的,使用註解其實是不明智的選擇,會大大消耗效能,影響應用的運行速度。小明看到這裡有點疑惑了,既然註解這麼影響效能,那為什麼Dagger2還要使用註解呢?為什麼Dagger2還這麼被廣泛的使用呢?
於是小明到github上查看Dagger2的介紹
官方介紹是
A fast dependency injector for Android and Java.
Dagger2是一個Android和Java中的快速注射器。
小明又疑惑了註解反射怎麼是快速的呢?
小明沒有灰心又繼續查看代碼,終於發現Dagger2是和其他依賴注入架構是有區別的,Dagger2是通過apt外掛程式在編譯階段產生注入代碼的,也就是說反射只是在編譯階段使用了,而在應用啟動並執行時候其實啟動並執行是真正的Java代碼並沒有涉及到註解反射,小明終於明白了,難怪Dagger2是快速注入架構。
小明有了這個重大發現後決定一鼓作氣把Dagger2產生的程式碼給理清楚。
編譯階段產生代碼
小明通過在Android studio中通過執行Build->Rebuild Project,在app/build/generated/source/apt目錄下發現產生了
LoginPresenterComp_Factory類
代碼如下
public final class LoginPresenterCompl_Factory implements Factory<LoginPresenterCompl> { private final Provider<ILoginView> viewProvider; public LoginPresenterCompl_Factory(Provider<ILoginView> viewProvider) { assert viewProvider != null; this.viewProvider = viewProvider; } @Override public LoginPresenterCompl get() { return new LoginPresenterCompl(viewProvider.get()); } public static Factory<LoginPresenterCompl> create(Provider<ILoginView> viewProvider) { return new LoginPresenterCompl_Factory(viewProvider); }}
為了對比小明又把LoginPresenterCompl的代碼也找了出來
代碼如下
public class LoginPresenterCompl implements ILoginPresenter { @Inject public LoginPresenterCompl(ILoginView view){ loginView = view ; user = new User("張三","123456") ; } ......}
仔細看看LoginPresenterCompl_Factory這個類,發現其中有三個方法
構造方法中的參數viewProvider一個Provider類型的,而Provider的泛型參數是ILoginView,這個參數就是我們執行個體化LoginPresenterCompl需要的參數,在上篇中我們知道了該參數是一個依賴,是由MainModule提供的。
在該方法中初始化了我們正在需要的LoginPresenterCompl對象
在該方法中執行個體化了LoginPresenterCompl_Factory本類對象
小明想既然上面的viewProvider是由MainModule提供的,那麼就來看看MainModule對應的注入類吧
MainModule_ProvideILogViewFactory
代碼如下
public final class MainModule_ProvideILogViewFactory implements Factory<ILoginView> { private final MainModule module; public MainModule_ProvideILogViewFactory(MainModule module) { assert module != null; this.module = module; } @Override public ILoginView get() { return Preconditions.checkNotNull( module.provideILogView(), "Cannot return null from a [email protected] @Provides method"); } public static Factory<ILoginView> create(MainModule module) { return new MainModule_ProvideILogViewFactory(module); }}
對應的MainModule代碼如下
@Modulepublic class MainModule { private final ILoginView view ; public MainModule(ILoginView view){ this.view = view ; } @Provides ILoginView provideILogView(){ return view ; }}
從結構中不難看出被@Provider註解修飾的方法會對應的產生Factory類,這個類中最主要的方法是get()方法,在該方法中調用了MainModule的provideILogView方法,而該方法是為了我們提供LoginPresenterCompl執行個體化參數的,LoginPresenterCompl的執行個體化是在LoginPresenterCompl_Factory的get()方法中完成的。
執行個體化代碼如下
@Overridepublic LoginPresenterCompl get() { return new LoginPresenterCompl(viewProvider.get());}
在代碼中可以看出執行個體化過程中參數是由viewProvider.get()提供的。咦!!!!
在MainModule_ProvideILogViewFactory中的get()方法其實返回了我們執行個體化的參數。
那麼這個viewProvider是不是我們的MainModule_ProvideILogViewFactory呢?
viewProvider是一個Provider類型,而MainModule_ProvideILogViewFactory實現了Factory介面,那Provider和Factory有沒有聯絡呢?
看這段代碼
public interface Factory<T> extends Provider<T> {}
發現Factory介面繼承了Provider介面,所以其實viewProvider就是MainModule_ProvideILogViewFactory類型。
看到這裡小明終於明白了LoginPresenterCompl_Factory類和MainModule_ProvideILoginViewFactory類的關係了,也明白了執行個體化過程了。
但是這些類的初始化和相關方法是如何被調用的,在哪裡被調用的呢?
還有兩個重要的類小明沒有看到。MainComponent和對應的DaggerMainComponent。
代碼如下
MainComponent代碼
@Component(modules = MainModule.class)public interface MainComponent { public void inject(LoginActivity activity) ;}
DaggerMainComponent代碼
public final class DaggerMainComponent implements MainComponent { private Provider<ILoginView> provideILogViewProvider; private Provider<LoginPresenterCompl> loginPresenterComplProvider; private MembersInjector<LoginActivity> loginActivityMembersInjector; private DaggerMainComponent(Builder builder) { assert builder != null; initialize(builder); } public static Builder builder() { return new Builder(); } @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.provideILogViewProvider = MainModule_ProvideILogViewFactory.create(builder.mainModule); this.loginPresenterComplProvider = LoginPresenterCompl_Factory.create(provideILogViewProvider); this.loginActivityMembersInjector = LoginActivity_MembersInjector.create(loginPresenterComplProvider); } @Override public void inject(LoginActivity activity) { loginActivityMembersInjector.injectMembers(activity); } public static final class Builder { private MainModule mainModule; private Builder() {} public MainComponent build() { if (mainModule == null) { throw new IllegalStateException(MainModule.class.getCanonicalName() + " must be set"); } return new DaggerMainComponent(this); } public Builder mainModule(MainModule mainModule) { this.mainModule = Preconditions.checkNotNull(mainModule); return this; } }}
通過上面代碼可以看出DaggerMainComponent實現了MainComponent介面並實現了其中的inject()方法。同時也提供了其他的輔助方法。
小明決定從方法調用順序開始入手查看
DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this);
注入過程
還記得在LoginActivity中添加的這個方法嗎,分析DaggerMainComponent就從這段代碼入手。
- 1、DaggerMainComponent調用了builder方法
小明找到builder()方法看看這個方法到底做了什麼事
public static Builder builder() { return new Builder();}
發現這個方法建立並返回了Builder對象
Builder是什麼東東呢?仔細看代碼Build是DaggerMainCompone的內部類。
- 2、DaggerMainComponent.builder().mainModule(new MainModule(this))
緊接著又調用了mainModule並將MainModule的對象傳了進來。
mainModule()方法是Builder中的一個方法,代碼如下
public Builder mainModule(MainModule mainModule) { this.mainModule = Preconditions.checkNotNull(mainModule); return this;}
其中做了什麼事呢?就是將傳進來的MainModule對象賦值給本類的mainModule對象,並返回本類對象
- 3、DaggerMainComponent.builder().mainModule(new MainModule(this)).build()
緊接著又調用了Builder的build()方法
public MainComponent build() { if (mainModule == null) { throw new IllegalStateException(MainModule.class.getCanonicalName() + " must be set"); } return new DaggerMainComponent(this);}
該方法通過new DaggerMainComponent(this)建立了DaggerMainComponent對象並將其返回。
那麼new DaggerMainComponent(this)做了什麼事呢?
private DaggerMainComponent(Builder builder) { assert builder != null; initialize(builder);}
其中調用了initialize方法並將builder對象傳入。
initialize()方法如下
private void initialize(final Builder builder) { this.provideILogViewProvider = MainModule_ProvideILogViewFactory.create(builder.mainModule); this.loginPresenterComplProvider = LoginPresenterCompl_Factory.create(provideILogViewProvider); this.loginActivityMembersInjector = LoginActivity_MembersInjector.create(loginPresenterComplProvider);}
在initialize方法中小明終於看到了MainModule_ProvideILogViewFactory和LoginPresenterCompl_Factory的create方法被調用了。
首先通過傳入的MainModule對象建立MainModule_ProvideILogViewFactory對象
provideILogViewProvider,然後將provideILogViewProvider對象作為參數來建立
LoginPresenterCompl_Factory對象。
前面已經講過,MainModule_ProvideILogViewFactory是一個Factory對象,
而LoginPresenterCompl_Factory建立對象需要一個Provider對象,同時Factory繼承了Provider,所以可以將其傳入。
所以LoginPresenterComp_Factory的viewProvider對象
是一個MainModule_ProvideILogViewFactory對象,
這個概念前面也講過,這裡得到認證。
在這段代碼中小明發現了LoginActivity_MembersInjector類,於是小明又將這個類找了出來
代碼如下
public final class LoginActivity_MembersInjector implements MembersInjector<LoginActivity> { private final Provider<LoginPresenterCompl> loginPresenterProvider; public LoginActivity_MembersInjector(Provider<LoginPresenterCompl> loginPresenterProvider) { assert loginPresenterProvider != null; this.loginPresenterProvider = loginPresenterProvider; } public static MembersInjector<LoginActivity> create( Provider<LoginPresenterCompl> loginPresenterProvider) { return new LoginActivity_MembersInjector(loginPresenterProvider); } @Override public void injectMembers(LoginActivity instance) { if (instance == null) { throw new NullPointerException("Cannot inject members into a null reference"); } instance.loginPresenter = loginPresenterProvider.get(); } public static void injectLoginPresenter( LoginActivity instance, Provider<LoginPresenterCompl> loginPresenterProvider) { instance.loginPresenter = loginPresenterProvider.get(); }}
該類的cereate()方法需要一個Provider泛型是LoginPresenterCompl類型的參數,通過建構函式將其傳入賦值給loginPresenterProvider變數。就這麼簡單。
- 4、DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this)
最後調用了inject()方法
@Overridepublic void inject(LoginActivity activity) { loginActivityMembersInjector.injectMembers(activity);}
在該方法中調用了LoginActivityMembersInjector中的injectMembers()方法。
injectMembers()方法內容如下
@Overridepublic void injectMembers(LoginActivity instance) { if (instance == null) { throw new NullPointerException("Cannot inject members into a null reference"); } instance.loginPresenter = loginPresenterProvider.get();}
終於!!!!!!!在這個方法中實現了對LoginPresenterCompl對象的初始化。
至此,小明終於能清楚了Dagger2的注入原理了,小明表示清楚原理後媽媽再也不用擔心Dagger2寫錯了。
如果沒有正確的分析這個產生的注入類可能很難理解Dagger2實現注入的架構,可能看原理代碼讓有些同學不知所措,相信我,多分析幾遍就OK了。
其實也不用糾結到底該如何使用Dagger2,只要我們理解了其實現的原理,具體如何使用看個人,能夠做到靈活使用就OK了。
至此Dagger2的原理分析就完成了。
總結
回顧一下該系列的文章
MVP模式講解
在MVP中使用Dagger2
Dagger2的注入原理解析
因為這三篇是連續的,代碼都是在前一篇的基礎上做的擴充,所以最好將三篇部落格通讀。
希望這三篇文章能夠幫到需要的同學,共同進步!!!
最後全部代碼點擊這裡
Android單排上王者系列之Dagger2注入原理解析