出來混早晚要還的,技術債Dagger2:Android篇(下)進一步理解Dagger

前言

警告!這不是一個乾貨的文章!java

我的認爲,學技術不宜太浮躁。對於一項技術一味地追求乾貨其實並不必定有用,貨太乾容易噎着,哈哈~不如按部就班慢下來,一點點去體會技術的來龍去脈。(這個系列適合於:瞭解但沒有在項目裏大規模應用Dagger2的讀者)app

出來混早晚要還的,技術債Dagger2:基礎篇框架

出來混早晚要還的,技術債Dagger2:Android篇(上)ide

出來混早晚要還的,技術債Dagger2:Android篇(中)@Scope、@Singletonpost

本覺得閱讀一些文檔,寫一些Demo就能駕馭工做中的項目...我錯了,我不再會有這麼愚蠢的想法了... 這麼多依賴關係,誰扛得住啊!因此仍是一點點來吧。學習

正文

前倆篇文章事後,我猜你們對下面的代碼已經很熟悉了:ui

@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
  void inject(MainActivity mainActivity);
  SharedPreferences getSharedPrefs();
}

@Module
public class AppModule {
    Application application;
 
    public AppModule(Application application) {
       this.application = application;
    }
 
    @Provides
    Application providesApplication() {
       return application;
    }
    
    @Provides
    @Singleton
    public SharedPreferences providePreferences() {
        return application.getSharedPreferences(DATA_STORE,Context.MODE_PRIVATE);
    }
}


DaggerAppComponent appComponent = DaggerAppComponent.builder()
     .appModule(new AppModule(this)) 
     .build();
複製代碼

很基本,很簡單的Dagger應用。不過你們有沒有感受到這個appModule(new AppModule(this))特別煩?安利我用的時候,說依賴注入,看不見new。我哼哧哼哧寫這麼多,這不仍是new出來的?this

那麼問題來了,是否是能夠不須要appModule(new AppModule(this))呢?固然能夠。用過Dagger-Android的朋友,確定很清楚,的確看不到任何new。那麼這篇文章,我們就來看看如何完全不用new。spa

固然這也是Dagger-Android的原理code

@Component.Builder

作這一切的前提是這個註解。這個註解是幹啥的呢?說白了,給Component提供Module的依賴。

我們先來想一個問題,下面代碼存在的意義:

DaggerAppComponent appComponent = DaggerAppComponent.builder()
     .appModule(new AppModule(this)) 
     .build();
複製代碼

Dagger爲咱們所需的依賴生成實例,那麼必然須要構建整個依賴關係網。Dagger就算是再神奇,也不可能憑空把整個咱們所須要依賴關係構建出來,因此須要咱們適時的「提供和引導」。那麼new AppModule(this)就是給Dagger進行提供,由於從咱們上述的代碼中,Dagger是不知道該怎麼去實例化這個AppModule,所以須要咱們對其進行提供。

那麼話又說回來,咱們在上述的代碼中,告訴它如何去實例化AppModule,不就能夠避免咱們手動去new AppModule(this)了麼?

沒錯,@Component.Builder就是作這個的。

累死了,繞了一圈不知道你們理沒理解@Component.Builder存在的含義了。

AppModule(Application application)

對於咱們的AppModule來講,實例化它的關鍵是如何提供一個Application

public AppModule(Application application) {
   this.application = application;
}
複製代碼

對於Dagger也是如此,它不能實例化AppModule的緣由是它不知道或者說沒辦法去獲取一個Application實例。所以,對於Dagger來講,咱們應該給它提供Application的實例,而非AppModule

開始改造

改造須要一步步來:第一步,咱們使用@Component.Builder去改造AppComponent

@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
   void inject(MainActivity mainActivity);
   SharedPreferences getSharedPrefs();
   // 改造內容
   @Component.Builder
   interface Builder {
        AppComponent build();
        // 此時還未改造這行代碼
        Builder appModule(AppModule appModule);
    }
}
複製代碼

如今咱們告訴了Dagger,你要以@Component.Builder註解的接口那樣去實例化咱們所需的AppComponent

是否是發現這裏添加的方法和DaggerAppComponent生成的代碼很像?沒錯Dagger默認實例化AppComponent就是以這種代碼進行的。

不過,對於咱們這個AppModule來講,咱們不須要關係它是怎麼初始化(由於咱們只須要它所提供給咱們的依賴)。對於Dagger來講也是如此: Dagger想要爲咱們提供被@Provides標註的依賴,只須要擁有Application實例便可。由於只要擁有Application實例Dagger就有辦法實例化AppModule,直接new便可。

因此這裏咱們須要一種方式來告訴Dagger:我要提供給你,在@Module中須要的內容。對於我們的這個demo來講,我們須要用一種方式把Dagger所須要的Application給他。

而作到這一點的就是@BindsInstance

@BindsInstance

按照官網的介紹,此註解用於標識Component Builder/SubComponent Builder中的某個方法,該方法容許將實例綁定到Component中。

因此對於咱們的AppModule來講,它只須要提供@Provides的內容就能夠了!,它所須要的,Dagger會按照咱們的「指示」,注入進來。也就是這個樣子:

@Module
public class AppModule {
     @Provides
     @Singleton
     // 外部傳入Application實例(Dagger會按照咱們的「指示」,注入進來)
     public SharedPreferences providePreferences(Application application) {
         return application.getSharedPreferences("store", Context.MODE_PRIVATE);
     }
 }
複製代碼

而咱們的AppConponent這樣就能夠了:

@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
   void inject(MainActivity mainActivity);
   SharedPreferences getSharedPrefs();
   @Component.Builder
   interface Builder {
        AppComponent build();
        @BindsInstance 
        // 此時的application就會被,注入到AppModule的providePreferences方法中
        Builder application(Application application);      
  }
}
複製代碼

build事後,咱們初始化DaggerAppComponent,只需如此寫:

DaggerAppComponent appComponent = DaggerAppComponent.builder()
   .application(this)
   .build();
複製代碼

那麼Dagger是如何爲咱們生成DaggerAppComponent的呢?

public final class DaggerAppComponent implements AppComponent {
  private Provider<Application> applicationProvider;

  private Provider<SharedPreferences> providePreferencesProvider;

  private DaggerAppComponent(Builder builder) {
    initialize(builder);
  }

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

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {
    this.applicationProvider = InstanceFactory.create(builder.application);
    this.providePreferencesProvider =
        DoubleCheck.provider(
            AppModule_ProvidePreferencesFactory.create(builder.appModule, applicationProvider));
  }

  @Override
  public void inject(MainActivity mainActivity) {}

  @Override
  public SharedPreferences getSharedPrefs() {
    return providePreferencesProvider.get();
  }

  private static final class Builder implements AppComponent.Builder {
    private AppModule appModule;

    private Application application;

    @Override
    public AppComponent build() {
      if (appModule == null) {
        this.appModule = new AppModule();
      }
      if (application == null) {
        throw new IllegalStateException(Application.class.getCanonicalName() + " must be set");
      }
      return new DaggerAppComponent(this);
    }

    @Override
    public Builder application(Application application) {
      this.application = Preconditions.checkNotNull(application);
      return this;
    }
  }
}
複製代碼

對於AppModule來講,只是簡單的new出來,當咱們須要@Provides時,只是將所需的application傳進去。而咱們的application以成員變量的身份呆在了DaggerAppComponent「體內」。

尾聲

這篇內容,其實並非爲了去講@Component.Builder@BindsInstance。而是儘量的經過它們,來加深你們去Component和Module的理解。去感覺Dagger的實現,更好的去理解依賴注入。對與咱們而言,須要用其形,學其神。

這樣咱們纔不會受制於框架,而是駕馭框架。

我是一個應屆生,最近和朋友們維護了一個公衆號,內容是咱們在從應屆生過渡到開發這一路所踩過的坑,以及咱們一步步學習的記錄,若是感興趣的朋友能夠關注一下,一同加油~

我的公衆號:鹹魚正翻身
相關文章
相關標籤/搜索