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 来暴露作为组件依赖的类(类似手动注入,很少用)
声明的方式有两种,选择简单的那种(以下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 的作用之一是实现单列,会改变生成代码
@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<OkHttpClient> {
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<OkHttpClient> 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