Android單排上王者系列之Dagger2注入原理解析

本篇文章已授權微信公眾號 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的注入原理解析因為這三篇是連續的,代碼都是在前一篇的基礎上做的擴展,所以最好將三篇博客通讀。希望這三篇文章能夠幫到需要的同學,共同進步?。?!
最后全部代碼點擊這里

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容