Dagger & Konlin

dagger 部分,参考

https://google.github.io/dagger/users-guide.html


总结下


声明依赖

方法一 在构造函数上加上 @Inject

class Thermosiphon implements Pump {
  private final Heater heater;

  @Inject
  Thermosiphon(Heater heater) {
    this.heater = heater;
  }

  ...
}

方法二 使用@Module 和 @Provide

@Module
class DripCoffeeModule {
  @Provides static Pump providePump(Thermosiphon pump) {
    return pump;
  }
}


两者的异同

1. 被标注的类作为依赖放入 object graph

2. @Inject 是全局依赖

    @Provider 依赖仅属于该 module

3. 接口没有构造函数,无法添加 @Inject

    第三方类无法修改,无法添加 @Inject

4. 所需参数会去 component 的 object graph 中寻找


Component

@Component(modules = DripCoffeeModule.class)
interface CoffeeShop {
  CoffeeMaker maker();
}
CoffeeShop coffeeShop = DaggerCoffeeShop.create();
coffeeShop.maker().brew();

component 负责注入依赖。

CoffeeShop 的 object graph 由两部分组成:全局依赖(@Inject)和 DripCoffeeModule 提供的依赖。


注入依赖的方式

1. @Inject @Provider 标注的参数会被自动注入

2. Provision-methods

像 CoffeeMaker maker() 这样,无参函数。

会去根据返回类型,去 object graph 中寻找并实例化,这是手动注入。(很少用)

3. Members-injection methods

有参函数,会为该参数的注入依赖。

这也是最常用的方法,方法名无所谓。

https://google.github.io/dagger/api/latest/dagger/Component.html#provision-methods


SubComponent

可以尝试整个应用只用一个注入器,但更好的实践是越小越好。

分散注入器职能的方式有两种: Component dependencies 和 SubComponent。

前者需要在 component 中写 provision methods 来暴露作为组件依赖的类(类似手动注入,很少用)


声明 SubComponent

声明的方式有两种,选择简单的那种(以下kotlin代码)

@Module
class MovieModule{
    @Provides
    fun movieApi(retrofit: Retrofit): MovieApi = retrofit.create(MovieApi::class.java)

    @Provides
    fun movieRepository(movieApi: MovieApi): MovieRepository = MovieRepositoryImpl(movieApi)
}
@Subcomponent(modules = arrayOf(MovieModule::class))
interface MovieComponent {
}

@Component(modules = arrayOf(AppModule::class))
interface AppComponent {
    fun getMovieComponent(): MovieComponent
}
只需要两步

1. 用 @SubComponent 替代 @Component。

2. 在 parent component 中声明  provision methods 暴露  sub component

如果 sub component 依赖的 module 不需要外部参数, module 参数都可以省略(会自动生成)。

object ComponentsHolder {

    private val appComponent: AppComponent by lazy { DaggerAppComponent.create() }

    val movieComponent: MovieComponent by lazy { appComponent.getMovieComponent() }

}
贴下生成的代码

    public AppComponent build() {
      if (appModule == null) {
        this.appModule = new AppModule();
      }
      return new DaggerAppComponent(this);
    }
    private MovieComponentImpl() {
      this.movieModule = new MovieModule();
      initialize();
    }


scope

scope 的作用之一是实现单列,会改变生成代码

    @Singleton
    @Provides
    fun okHttpClient(): OkHttpClient = OkHttpClient.Builder()
            .connectTimeout(60, TimeUnit.SECONDS)
            .readTimeout(60, TimeUnit.SECONDS)
            .build()

    this.okHttpClientProvider =
        DoubleCheck.provider(AppModule_OkHttpClientFactory.create(builder.appModule));

public final class AppModule_OkHttpClientFactory implements Factory {
  private final AppModule module;

  public AppModule_OkHttpClientFactory(AppModule module) {
    assert module != null;
    this.module = module;
  }

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

  public static Factory create(AppModule module) {
    return new AppModule_OkHttpClientFactory(module);
  }
}
实现单列的原理是 DoubleCheck。


component 可以用 scope 标注,遵循两个原则

1. component 只能注入无 scope 或者相同 scope 的依赖。

2. 不同 component 不能使用相同的 scope。


scope 划分了另一种归属性质,比 module 细度更高,直接作用于依赖本身。

(实际上 sub component 能够注入不同 scope 的依赖,通过 parent component )

@Scope
@MustBeDocumented
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
annotation class App
假设 sub com install sub module,sub module 提供三种依赖 @Sub @Other 无Scope

app com install app module, sub com 是 app com 的 subcompent

则 sub com 可注入依赖为: sub module 中 @Sub  无Scope, app com 可注入的依赖,全局依赖中 @Sub 无Scope。


Qualifiers

有时候会需要多个单列,retrofit 不提供修改 baseUrl 的方法。

如果需要连接多个服务器,就要持有多个 retrofit 单列。

@Module
class AppModule {

    @Named("t")
    @App
    @Provides
    fun okHttpClient(): OkHttpClient = OkHttpClient.Builder()
            .connectTimeout(60, TimeUnit.SECONDS)
            .readTimeout(60, TimeUnit.SECONDS)
            .build()

    private val baseUrl = "http://v.juhe.cn/movie/"

    @App
    @Provides
    fun retrofit(@Named("s") client: OkHttpClient): Retrofit = Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create(Gson()))
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build()

}
这样运行会报错,因为只提供了名为 t 的 okHttpClient 单列。


Dagger Android

https://google.github.io/dagger/android.html






你可能感兴趣的:(Konlin)