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

來源:互聯網
上載者:User

標籤:

本篇文章已授權公眾號 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 [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注入原理解析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.