Dagger2詳解-從代碼分析其原理

Dagger2基本概念請(qǐng)移步官方文檔,或者我的翻譯。

架構(gòu)方面請(qǐng)關(guān)注GitHub(MVP+Retrofit+Dagger2+Okhttp)及我的文章Android UI框架快速搭建實(shí)踐

Dagger2是Dagger1的分支,由谷歌公司接手開發(fā),目前的版本是2.0。Dagger2解決問題的基本思想是:利用生成和寫的代碼混合達(dá)到看似所有的產(chǎn)生和提供依賴的代碼都是手寫的樣子。

如果我們將Dagger2和1比較,他們兩個(gè)在很多方面都非常相似,但也有很重要的區(qū)別,如下:

  1. 再也沒有使用反射:圖的驗(yàn)證、配置和預(yù)先設(shè)置都在編譯的時(shí)候執(zhí)行。
  1. 容易調(diào)試和可跟蹤:完全具體地調(diào)用提供和創(chuàng)建的堆棧
  2. 更好的性能:谷歌聲稱他們提高了13%的處理性能
  3. 代碼混淆:使用派遣方法,就如同自己寫的代碼一樣

當(dāng)然所有這些很棒的特點(diǎn)都需要付出一個(gè)代價(jià),那就是缺乏靈活性,例如:Dagger2沒用反射所以沒有動(dòng)態(tài)機(jī)制。

所以在Android UI框架快速搭建實(shí)踐這篇文章中,因?yàn)槲覍resenter作為泛型成員變量抽取到BaseFragment中了,所以View層的Presenter無(wú)法使用Dagger2實(shí)現(xiàn)注入。如果要實(shí)現(xiàn)Presenter注入,則需要在每個(gè)View實(shí)現(xiàn)中注入對(duì)應(yīng)的Presenter實(shí)例,這樣就無(wú)法抽取到基類中了。這個(gè)在具體實(shí)踐中,需要你自己權(quán)衡。

本文就GitHub項(xiàng)目,從生成的代碼對(duì)Dagger2進(jìn)行分析。

使用Dagger2,在module的gradle中配置:

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

android{
    ...
}
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        //添加apt插件
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.google.dagger:dagger:2.4'
    apt 'com.google.dagger:dagger-compiler:2.4'
    ...
 }

使用時(shí),定義好component及module后,build工程,Dagger2編譯器就會(huì)生成對(duì)應(yīng)代碼,然后在需要注入的地方調(diào)用生成的component實(shí)現(xiàn),名為Dagger前綴+component名稱的類完成綁定。

先看結(jié)構(gòu)圖:

dagger2.png

大概介紹一下基本概念:

  • Module:使用@Module注解,封裝@Provides方法,@Provides注解方法提供依賴對(duì)象。

  • @Inject:在需要依賴注入的地方使用。Dagger2提供3種方式:

    • 構(gòu)造方法注入:在類的構(gòu)造方法前面注釋@Inject
    • 成員變量注入:在類的成員變量(非私有)前面注釋@Inject
    • 函數(shù)方法注入:在函數(shù)前面注釋@Inject
  • @Peractivity:自定義scope注解,約束依賴對(duì)象的生命周期。

  • @Singleton:api提供的scope注解,保證對(duì)象在對(duì)象圖中唯一。

  • Component:使用@Component注解的接口,是@Inject和@Module聯(lián)系的橋梁,子component可以使用@Subcomponent也可以指定@Component的dependency參數(shù)。

是時(shí)候上代碼了(Dagger2生成的代碼在build/generated/source/apt/目錄下):

DemoApplicationModule的定義:

@Module
public class DemoApplicationModule {
  private final Application application;

  public DemoApplicationModule(Application application) {
    this.application = application;
  }

  /**
   * Expose the application to the graph.
   */
  @Provides @Singleton Application application() {
    return application;
  }

  @Provides @Singleton LocationManager provideLocationManager() {
    return (LocationManager) application.getSystemService(LOCATION_SERVICE);
  }
}

來(lái)看生成的代碼:

public final class DemoApplicationModule_ApplicationFactory implements Factory<Application> {
  private final DemoApplicationModule module;

  public DemoApplicationModule_ApplicationFactory(DemoApplicationModule module) {
    assert module != null;
    this.module = module;
  }

  @Override
  public Application get() {
    return Preconditions.checkNotNull(
        module.application(), "Cannot return null from a non-@Nullable @Provides method");
  }

  public static Factory<Application> create(DemoApplicationModule module) {
    return new DemoApplicationModule_ApplicationFactory(module);
  }
}   
----------------
public final class DemoApplicationModule_ProvideLocationManagerFactory
    implements Factory<LocationManager> {
  private final DemoApplicationModule module;

  public DemoApplicationModule_ProvideLocationManagerFactory(DemoApplicationModule module) {
    assert module != null;
    this.module = module;
  }

  @Override
  public LocationManager get() {
    return Preconditions.checkNotNull(
        module.provideLocationManager(),
        "Cannot return null from a non-@Nullable @Provides method");
  }

  public static Factory<LocationManager> create(DemoApplicationModule module) {
    return new DemoApplicationModule_ProvideLocationManagerFactory(module);
  }
}

module中定義的@Provides方法會(huì)生成對(duì)應(yīng)的工廠類,實(shí)現(xiàn)Factory<T>接口,復(fù)寫get()方法,get()中實(shí)際調(diào)用了module的provide方法,那module實(shí)例從哪里來(lái)的呢,看工廠類的創(chuàng)建方法中,看來(lái)這個(gè)module對(duì)象是需要外部傳入的。

ApplicationComponent定義:

@Singleton  
@Component(modules = DemoApplicationModule.class)
public interface ApplicationComponent {
  // Field injections of any dependencies of the DemoApplication
  void inject(DemoApplication application);

  // Exported for child-components.
  Application application();
  LocationManager locationManager();
}

生成的代碼:

public final class DaggerApplicationComponent implements ApplicationComponent {
  private Provider<LocationManager> provideLocationManagerProvider;

  private MembersInjector<DemoApplication> demoApplicationMembersInjector;

  private Provider<Application> applicationProvider;

  private DaggerApplicationComponent(Builder builder) {
    assert builder != null;
    initialize(builder);
  }

  public static Builder builder() {
    return new Builder();
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {

    this.provideLocationManagerProvider =
        DoubleCheck.provider(
            DemoApplicationModule_ProvideLocationManagerFactory.create(
                builder.demoApplicationModule));

    this.demoApplicationMembersInjector =
        DemoApplication_MembersInjector.create(provideLocationManagerProvider);

    this.applicationProvider =
        DoubleCheck.provider(
            DemoApplicationModule_ApplicationFactory.create(builder.demoApplicationModule));
  }

  @Override
  public void inject(DemoApplication application) {
    demoApplicationMembersInjector.injectMembers(application);
  }

  @Override
  public Application application() {
    return applicationProvider.get();
  }

  @Override
  public LocationManager locationManager() {
    return provideLocationManagerProvider.get();
  }

  public static final class Builder {
    private DemoApplicationModule demoApplicationModule;

    private Builder() {}

    public ApplicationComponent build() {
      if (demoApplicationModule == null) {
        throw new IllegalStateException(
            DemoApplicationModule.class.getCanonicalName() + " must be set");
      }
      return new DaggerApplicationComponent(this);
    }

    public Builder demoApplicationModule(DemoApplicationModule demoApplicationModule) {
      this.demoApplicationModule = Preconditions.checkNotNull(demoApplicationModule);
      return this;
    }
  }
}   

DaggerApplicationComponent內(nèi)部生成了Builder類,通過Builder的build()可以得到DaggerApplicationComponent對(duì)象,但必須先傳入DemoApplicationModule對(duì)象,這是當(dāng)然的,Component本來(lái)就只是一個(gè)橋梁而已,別忘了之前定義ApplicationComponent的注解@Component(modules = DemoApplicationModule.class),這樣就好理解了吧。

調(diào)用了Builder的build()后,會(huì)走DaggerApplicationComponent的構(gòu)造器方法,這里調(diào)用了initialize(builder), initialize(builder)又干了什么呢?這里初始化了待注入的依賴對(duì)象locationManager和application,通過之前的工廠類的create()方法得到工廠類對(duì)象,工廠類是實(shí)現(xiàn)Factory<T>接口的,F(xiàn)actory<T>又是繼承Provider<T>的,所以這里相當(dāng)于拿到的是封裝了不同對(duì)象的Provider實(shí)例, DoubleCheck.provider(provider)又干了什么呢?DoubleCheck也實(shí)現(xiàn)了Provider<T>,它的provider(provider)方法實(shí)際上返回了本身實(shí)例,實(shí)際上也是一個(gè)Provider<T>,但為什么要這么做呢?看代碼:

public static <T> Provider<T> provider(Provider<T> delegate) {
...    
    return new DoubleCheck<T>(delegate);
}
  
private DoubleCheck(Provider<T> provider) {
    assert provider != null;
    this.provider = provider;
}

public T get() {
    Object result = instance;
    if (result == UNINITIALIZED) {
      synchronized (this) {
        result = instance;
        if (result == UNINITIALIZED) {
          instance = result = provider.get();
        provider = null;
        }
      }
    }
    return (T) result;
  }

provider(Provider<T> delegate)調(diào)用了構(gòu)造器方法,構(gòu)造器中將傳入的Provider對(duì)象保存起來(lái)了,調(diào)用get()時(shí)會(huì)調(diào)用保存的provider對(duì)象的get(),實(shí)際上就是調(diào)用工廠方法的get()拿到對(duì)象,這樣就實(shí)現(xiàn)了懶加載,在需要的時(shí)候調(diào)用get(),這時(shí)才會(huì)調(diào)用工廠方法的get(),因?yàn)檎嬲齽?chuàng)建對(duì)象的細(xì)節(jié)是封裝在工廠類的get()中的,同時(shí),它會(huì)將得到的對(duì)象緩存起來(lái),這樣下次調(diào)用就不需要再調(diào)用工廠類創(chuàng)建對(duì)象了。

再看注入的地方:

public class DemoApplication extends Application {
  private ApplicationComponent applicationComponent;

  @Inject LocationManager locationManager;  
  @Override public void onCreate() {
    super.onCreate();
    applicationComponent = DaggerApplicationComponent.builder()
        .demoApplicationModule(new DemoApplicationModule(this))
        .build();
  }

  public ApplicationComponent component() {
    return applicationComponent;
  }
}

這里需要注入locationMnager,我們?cè)倏锤鶕?jù)@Inject生成的代碼:

public final class DemoApplication_MembersInjector implements MembersInjector<DemoApplication> {
  private final Provider<LocationManager> locationManagerProvider;

  public DemoApplication_MembersInjector(Provider<LocationManager> locationManagerProvider) {
    assert locationManagerProvider != null;
    this.locationManagerProvider = locationManagerProvider;
  }

  public static MembersInjector<DemoApplication> create(
      Provider<LocationManager> locationManagerProvider) {
    return new DemoApplication_MembersInjector(locationManagerProvider);
  }

  @Override
  public void injectMembers(DemoApplication instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.locationManager = locationManagerProvider.get();
  }

  public static void injectLocationManager(
      DemoApplication instance, Provider<LocationManager> locationManagerProvider) {
    instance.locationManager = locationManagerProvider.get();
  }
}

injectMembers(DemoApplication instance) 方法將locationManager對(duì)象賦值給DemoApplication對(duì)象,DemoApplication和locationManagerProvider從哪里來(lái)呢?上面DaggerApplicationComponent的initialize(builder)中實(shí)例化了DemoApplication_MembersInjector并傳入需要的參數(shù)。

DaggerApplicationComponent實(shí)現(xiàn)了ApplicationComponent,當(dāng)然要復(fù)寫其方法。
在DemoApplication中調(diào)用DaggerApplicationComponent的inject()方法,然后就會(huì)調(diào)用DemoApplication_MembersInjector的injectMembers(DemoApplication instance),就實(shí)現(xiàn)了依賴注入。

那DaggerApplicationComponent的其他方法呢?比如locationManager(),application()等呢,這些方法是在定義在ApplicationComponent中的,子component是共享父component中的綁定的,那子component怎么拿到父component中的依賴對(duì)象呢?

 this.locationManagerProvider =
        new Factory<LocationManager>() {
          private final ApplicationComponent applicationComponent = builder.applicationComponent;

          @Override
          public LocationManager get() {
            return Preconditions.checkNotNull(
                applicationComponent.locationManager(),
                "Cannot return null from a non-@Nullable component method");
          }
        };

在DaggerHomeComponent的initialize(final Builder builder)中通過applicationComponent.locationManager,子component就也有l(wèi)ocationManager實(shí)例了。

Activity的依賴注入分析也是類似的,通過源碼,我們可以清晰的跟蹤其調(diào)用流程。

That's all!希望能幫到你。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容