出来混早晚要还的,技术债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的实现,更好的去理解依赖注入。对与咱们而言,须要用其形,学其神。

这样咱们才不会受制于框架,而是驾驭框架。

我是一个应届生,最近和朋友们维护了一个公众号,内容是咱们在从应届生过渡到开发这一路所踩过的坑,以及咱们一步步学习的记录,若是感兴趣的朋友能够关注一下,一同加油~

我的公众号:咸鱼正翻身
相关文章
相关标签/搜索