本篇文章已授權微信公眾號 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提供的。
- get()方法
在該方法中初始化了我們正在需要的LoginPresenterCompl對象
- create()方法
在該方法中實例化了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 non-@Nullable @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()方法中完成的。實例化代碼如下
@Override
public 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()方法
@Override
public void inject(LoginActivity activity) {
loginActivityMembersInjector.injectMembers(activity);
}
在該方法中調用了LoginActivityMembersInjector中的injectMembers()方法。injectMembers()方法內容如下
@Override
public 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的注入原理解析因為這三篇是連續的,代碼都是在前一篇的基礎上做的擴展,所以最好將三篇博客通讀。希望這三篇文章能夠幫到需要的同學,共同進步?。?!
最后全部代碼點擊這里