本篇文章已授權(quán)微信公眾號(hào) guolin_blog (郭霖)獨(dú)家發(fā)布
MVP模式講解
在MVP中使用Dagger2
Dagger2的注入原理解析
在上篇博客中我們介紹了Dagger2該如何在項(xiàng)目中使用啤呼,這篇博客將繼續(xù)分析Dagger2實(shí)現(xiàn)的原理,代碼依然采用上篇的代碼,看這里贡定。
Dagger2的注入原理
原理的講解我們通過小明來(lái)帶我們學(xué)習(xí)憎账。
小明在看了MVP的實(shí)戰(zhàn)解析和Dagger2的使用后知道了Dagger2該如何在MVP模式中使用,但是小明是一個(gè)要求上進(jìn)的好同學(xué)晨炕,小明并不滿足于如何使用蒸播,小明想鉆研鉆研源碼,看看如何實(shí)現(xiàn)的场航。小明在鉆研Dagger2的時(shí)候突然意識(shí)到Dagger2是采用注解的形式完成任務(wù)的缠导,使用注解其實(shí)是不明智的選擇,會(huì)大大消耗性能溉痢,影響應(yīng)用的運(yùn)行速度僻造。
小明看到這里有點(diǎn)疑惑了,既然注解這么影響性能孩饼,那為什么Dagger2還要使用注解呢髓削?為什么Dagger2還這么被廣泛的使用呢?
于是小明到github上查看Dagger2的介紹
官方介紹是
A fast dependency injector for Android and Java.
Dagger2是一個(gè)Android和Java中的快速注射器镀娶。
小明又疑惑了注解反射怎么是快速的呢立膛?小明沒有灰心又繼續(xù)查看代碼,終于發(fā)現(xiàn)Dagger2是和其他依賴注入框架是有區(qū)別的梯码,Dagger2是通過apt插件在編譯階段生成注入代碼的宝泵,也就是說(shuō)反射只是在編譯階段使用了,而在應(yīng)用運(yùn)行的時(shí)候其實(shí)運(yùn)行的是真正的Java代碼并沒有涉及到注解反射轩娶,小明終于明白了儿奶,難怪Dagger2是快速注入框架。
小明有了這個(gè)重大發(fā)現(xiàn)后決定一鼓作氣把Dagger2生成的代碼給理清楚罢坝。
編譯階段生成代碼
小明通過在Android studio中通過執(zhí)行Build->Rebuild Project廓握,在app/build/generated/source/apt目錄下發(fā)現(xiàn)生成了
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);
}
}
為了對(duì)比小明又把LoginPresenterCompl的代碼也找了出來(lái)代碼如下
public class LoginPresenterCompl implements ILoginPresenter {
@Inject
public LoginPresenterCompl(ILoginView view){
loginView = view ;
user = new User("張三","123456") ;
}
......
}
仔細(xì)看看LoginPresenterCompl_Factory這個(gè)類,發(fā)現(xiàn)其中有三個(gè)方法
- 構(gòu)造方法
構(gòu)造方法中的參數(shù)viewProvider一個(gè)Provider類型的嘁酿,而Provider的泛型參數(shù)是ILoginView隙券,這個(gè)參數(shù)就是我們實(shí)例化LoginPresenterCompl需要的參數(shù),在上篇中我們知道了該參數(shù)是一個(gè)依賴闹司,是由MainModule提供的娱仔。
- get()方法
在該方法中初始化了我們正在需要的LoginPresenterCompl對(duì)象
- create()方法
在該方法中實(shí)例化了LoginPresenterCompl_Factory本類對(duì)象
小明想既然上面的viewProvider是由MainModule提供的,那么就來(lái)看看MainModule對(duì)應(yīng)的注入類吧
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);
}
}
對(duì)應(yīng)的MainModule代碼如下
@Modulepublic
class MainModule {
private final ILoginView view ;
public MainModule(ILoginView view){
this.view = view ;
}
@Provides
ILoginView provideILogView(){
return view ;
}
}
從結(jié)構(gòu)中不難看出被@Provider注解修飾的方法會(huì)對(duì)應(yīng)的生成Factory類游桩,這個(gè)類中最主要的方法是get()方法牲迫,在該方法中調(diào)用了MainModule的provideILogView方法,而該方法是為了我們提供LoginPresenterCompl實(shí)例化參數(shù)的借卧,LoginPresenterCompl的實(shí)例化是在LoginPresenterCompl_Factory的get()方法中完成的盹憎。實(shí)例化代碼如下
@Override
public LoginPresenterCompl get() {
return new LoginPresenterCompl(viewProvider.get());
}
在代碼中可以看出實(shí)例化過程中參數(shù)是由viewProvider.get()提供的。咦n砹酢E忝俊!!
在MainModule_ProvideILogViewFactory中的get()方法其實(shí)返回了我們實(shí)例化的參數(shù)檩禾。那么這個(gè)viewProvider是不是我們的MainModule_ProvideILogViewFactory呢挂签?
viewProvider是一個(gè)Provider類型,而MainModule_ProvideILogViewFactory實(shí)現(xiàn)了Factory接口盼产,那Provider和Factory有沒有聯(lián)系呢饵婆?
看這段代碼
public interface Factory<T> extends Provider<T> {
}
發(fā)現(xiàn)Factory接口繼承了Provider接口,所以其實(shí)viewProvider就是MainModule_ProvideILogViewFactory類型戏售∏群耍看到這里小明終于明白了LoginPresenterCompl_Factory類和MainModule_ProvideILoginViewFactory類的關(guān)系了,也明白了實(shí)例化過程了蜈项。但是這些類的初始化和相關(guān)方法是如何被調(diào)用的芹关,在哪里被調(diào)用的呢?
還有兩個(gè)重要的類小明沒有看到紧卒。MainComponent和對(duì)應(yīng)的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實(shí)現(xiàn)了MainComponent接口并實(shí)現(xiàn)了其中的inject()方法。同時(shí)也提供了其他的輔助方法跑芳。小明決定從方法調(diào)用順序開始入手查看
DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this);
注入過程
還記得在LoginActivity中添加的這個(gè)方法嗎轴总,分析DaggerMainComponent就從這段代碼入手。
- 1博个、DaggerMainComponent調(diào)用了builder方法
小明找到builder()方法看看這個(gè)方法到底做了什么事
public static Builder builder() { return new Builder();}
發(fā)現(xiàn)這個(gè)方法創(chuàng)建并返回了Builder對(duì)象Builder是什么東東呢怀樟?仔細(xì)看代碼Build是DaggerMainCompone的內(nèi)部類。
- 2盆佣、DaggerMainComponent.builder().mainModule(new MainModule(this))
緊接著又調(diào)用了mainModule并將MainModule的對(duì)象傳了進(jìn)來(lái)往堡。mainModule()方法是Builder中的一個(gè)方法,代碼如下
public Builder mainModule(MainModule mainModule) { this.mainModule = Preconditions.checkNotNull(mainModule); return this;}
其中做了什么事呢共耍?就是將傳進(jìn)來(lái)的MainModule對(duì)象賦值給本類的mainModule對(duì)象虑灰,并返回本類對(duì)象
- 3、DaggerMainComponent.builder().mainModule(new MainModule(this)).build()
緊接著又調(diào)用了Builder的build()方法
public MainComponent build() { if (mainModule == null) {
throw new IllegalStateException(MainModule.class.getCanonicalName() + " must be set");
}
return new DaggerMainComponent(this);
}
該方法通過new DaggerMainComponent(this)創(chuàng)建了DaggerMainComponent對(duì)象并將其返回痹兜。那么new DaggerMainComponent(this)做了什么事呢穆咐?
private DaggerMainComponent(Builder builder) { assert builder != null; initialize(builder);}
其中調(diào)用了initialize方法并將builder對(duì)象傳入。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方法被調(diào)用了字旭。
首先通過傳入的MainModule對(duì)象創(chuàng)建MainModule_ProvideILogViewFactory對(duì)象provideILogViewProvider对湃,然后將provideILogViewProvider對(duì)象作為參數(shù)來(lái)創(chuàng)建LoginPresenterCompl_Factory對(duì)象。
前面已經(jīng)講過遗淳,MainModule_ProvideILogViewFactory是一個(gè)Factory對(duì)象拍柒,而LoginPresenterCompl_Factory創(chuàng)建對(duì)象需要一個(gè)Provider對(duì)象,同時(shí)Factory繼承了Provider屈暗,所以可以將其傳入拆讯。所以LoginPresenterComp_Factory的viewProvider對(duì)象是一個(gè)MainModule_ProvideILogViewFactory對(duì)象剧包,這個(gè)概念前面也講過,這里得到認(rèn)證往果。
在這段代碼中小明發(fā)現(xiàn)了LoginActivity_MembersInjector類,于是小明又將這個(gè)類找了出來(lái)代碼如下
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()方法需要一個(gè)Provider泛型是LoginPresenterCompl類型的參數(shù)一铅,通過構(gòu)造函數(shù)將其傳入賦值給loginPresenterProvider變量陕贮。就這么簡(jiǎn)單。
- 4潘飘、DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this)
最后調(diào)用了inject()方法
@Override
public void inject(LoginActivity activity) {
loginActivityMembersInjector.injectMembers(activity);
}
在該方法中調(diào)用了LoginActivityMembersInjector中的injectMembers()方法肮之。injectMembers()方法內(nèi)容如下
@Override
public void injectMembers(LoginActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.loginPresenter = loginPresenterProvider.get();
}
終于!2仿肌8昵堋!<瓒尽?鸶摺!在這個(gè)方法中實(shí)現(xiàn)了對(duì)LoginPresenterCompl對(duì)象的初始化丑瞧。
至此柑土,小明終于弄清楚了Dagger2的注入原理了,小明表示清楚原理后媽媽再也不用擔(dān)心Dagger2寫錯(cuò)了绊汹。
如果沒有正確的分析這個(gè)生成的注入類可能很難理解Dagger2實(shí)現(xiàn)注入的框架稽屏,可能看原理代碼讓有些同學(xué)不知所措,相信我西乖,多分析幾遍就OK了狐榔。
其實(shí)也不用糾結(jié)到底該如何使用Dagger2,只要我們理解了其實(shí)現(xiàn)的原理获雕,具體如何使用看個(gè)人薄腻,能夠做到靈活使用就OK了。
至此Dagger2的原理分析就完成了典鸡。
總結(jié)
回顧一下該系列的文章
MVP模式講解
在MVP中使用Dagger2
Dagger2的注入原理解析因?yàn)檫@三篇是連續(xù)的被廓,代碼都是在前一篇的基礎(chǔ)上做的擴(kuò)展,所以最好將三篇博客通讀萝玷。希望這三篇文章能夠幫到需要的同學(xué)嫁乘,共同進(jìn)步!G虻铩蜓斧!
最后全部代碼點(diǎn)擊這里