目录
0. 前言
1. 依赖与注入
2. @Inject
3. @Module & @Provides
4. @Component
5. @Qualifier
6. Provider & Lazy
7. @Scope
8. 注入到Set和Map容器
9. Bind系列注解
10. dagger中依赖关系与继承关系
11. dagger.android
目标
上一篇说到我们想要dagger自动生成出类似于我们手写的Bridge
桥接类,本文就是对实现此功能的@Component
做一个简介分析,来看看dagger中怎样使用@Component
吧
依赖图
在介绍本篇主角@Component
之前,我们先根据已有代码画一个依赖图:(个人认为使用dagger就必须要弄清楚自己的依赖图,无论是画在纸上还是在脑海中,一定要想清楚再编写dagger)
如上图所示:
- 实线箭头表示依赖关系,虚线箭头表示提供数据,直角框表示对象,圆角框表示数据仓库
- 被
@Inject
注解的构造函数中的参数,也算做这个对象的依赖,比如Computer
的os
和price
- 和
@Inject
一样,被@Provides
注解的方法中的参数也是一个依赖,不过这个依赖是被@Module
注解的数据仓库的依赖,比如provideMemory()
中的size
从上面依赖图中可以看到,os
、price
、size
这三个依赖是没有数据来源的,回想下我们自己写的Bridge
,这三个依赖其实都是我们手写(hardcode)传入工厂方法中的,如果想dagger帮我们生成这个Bridge
,就要让dagger去调用工厂方法,那么怎样让dagger知道工厂方法中需要传入Windos
、6666
和8192
这三个参数呢?这里有两个思路:
- 为上述三个依赖都创建数据仓库,比如
OsModule
、PriceModule
、SizeModule
。但PriceModule
和SizeModule
都是提供Int
型数据,怎样让dagger知道PriceModule
提供的Int
实例是给Computer
的price
依赖,而SizeModule
提供的Int
实例是个MemoryModule
的size
依赖?怎样解决这种问题以后会说到,这里先留个悬念 - 既然被
@Inject
注解的构造函数中的参数和被@Provides
注解的方法中的参数都算依赖,那么我们直接将构造函数和provide方法变成无参的不就好了?比如在Computer
的init{}
中去给os
和price
赋值,或者将size
作为Module
的成员变量而不是provide方法的参数。前者修改Computer
类很明显降低了类的灵活性,而且之前也说过@Inject
无法用于三方库或系统中对象的构造函数,所以我们采取后者来解决提供依赖的问题
首先将Computer
构造函数上的@Inject
去掉,并为Computer
新建数据仓库ComputerModule
类,之后修改MemoryModule
添加成员变量并使@Provides
注解的方法变为无参:
@Module
class ComputerModule(private val os: String, private val price: Int) {
@Provides
fun provideComputer() = Computer(os, price)
}
@Module
class MemoryModule(private val size: Int) {
@Provides
fun provideMemory() = Memory(size)
}
编译一下,你会发现现在生成的工厂类,就和上一篇中无参的@Provides
生成的工厂类一模一样了,这里可以思考下为什么dagger生成的工厂类是对数据仓库(Module)的代理工厂,而不是直接创建数据仓库实例,一切都是为了解耦提高灵活性(下面仅贴出MemoryModule_ProvideMemoryFactory
作为对比,ComputerModule_ProvideMemoryFactory
整体上大同小异就不再贴出来了)
public final class MemoryModule_ProvideMemoryFactory implements Factory<Memory> {
private final MemoryModule module;
public MemoryModule_ProvideMemoryFactory(MemoryModule module) {
this.module = module;
}
@Override