@Inject :
这个注解有两种使用方式,一种是注解类的构造函数,一种是注解类的成员变量。
先说下第一种,在类的构造函数上注解的作用是为了创建一个当前类的工厂类。
第二种,在类的成员变量上注解是为了创建一个当前类的成员注入对象。
@Inject 注解的两个功能基本上已经明确了,一是 为了提供被注入的对象,二是提供注入到当前类的对象。
@Provides
这个注解使用起来比较简单,主要的作用是为了弥补@Inject注解的不足,因为@Inject在提供注入对象的时候必须要在构造函数上注解,那么这就存在局限。@Provides就是为了弥补这种局限的。
可以看到构造函数中需要所在的Module 对象,下面再说说这个module。
@Provides 注解的功能就是标注提供被注入的对象的方法,是为了弥补@Inject 注解出现的。
@Module
@Module注解在我看来就是提供一个场所,用来生成被注入的对象的场所,由上文可以知道我们可以用过两种方式提供被注入的对象,@Inject 标识构造函数,@Provides 标识提供注入对象的方法。但是如果在整个项目中任意位置这么写的话,我想这个工作量可能会很巨大,所以就出现了Module注解,一是为了整理归拢当前需要的提供的注入对象,二是便于维护,当前module内的可以互相提供。
提问:
不同module ,相同component中的是否可以互相提供? 这个都等Component之后在回答。
通过@Module 标记的类不会生成新的代码。
@Component
现在我们来整理一下我们目前有的东西,
一个是通过@Inject注解构造函数的被注入对象提供工具。
一个是通过@Provides注解的被注入对象的方法工具。
一个是提供注入对象的场所。
一个是通过@Inject注解成员变量的当前类的注入对象工具
那么我们现在缺少一个东西,来讲提供的对象注入的指定的类中,那就是@Component, 它可以知道它能从哪些地方来获取被注入的对象,它有一个方法能够调用当前类的注入工具去注入对象。更具体的说它的作用是将提供注入对象的场所和要去注入的类建立连接。
可以看到它通过Builder对象进行初始化,初始化的时候会需要一个Module , 不过已经被标记为废弃了,之后会给它的成员变量赋值。成员变量时注入接口的泛型对象,泛型类型就是在写inject方法的时候的参数类型,这个成员变量会通过之前的@Inject 方法标注的成员变量编译出来的注入工具生成。通过创建的时候也需要一个Proivder<T>泛型对象,这里直接就是通过@Inject 注解的构造函数编译出来的工具生成。
接下来看看两个对象的情况:
我们只关注改变,只有成员注入工具类和连接Component 发生改变
第一个发生变化的是注入工具的构造函数变成了两个参数,并且注入的函数变成了三个。这些是注入工具的改变.。
这里看到主要有两个变化,按照调用顺序来分析。
首先在生成Builder的时候现在必须会持有一个UserModule 了,之前的时候是没有的。
其次是在initialize的时候,会先通过Builder的Moudle去生成一个通过@Provides 注解的注入工具类,然后把这个生成的工具类和之前的Inject生成的工具类一起给Activity的注入工具类。
回答之前的问题:
答案是可以的,在同一个Component 下的module中的代码是可以互相依赖的。
下面说一下为什么?
我只取了比较重要的的地方,可以看到,之前的时候在类成员注入工具在使用的时候必须有两个注入对象的提供类,并且全是泛型的接口对象,这就有很大的优势。之前提供的是userModule, 现在的则是persionmodule, 而实现改变的方式就是在Builder中,看来Builder中会持有所有的拥有provides注解的module 成员。这就是为了在注入的时候能够通过对应module生成注入对象提供工具。这一个简单的注入实现就完成。之后的更多的注解,包括@scope ,@subcomponent,等都是提供更多的变化, 基本的逻辑是不会改变的。
@Singleton
Dagger提供的@scope注解注解的一种,简单来说就是单例。但是说一下具体的要求或者说功能:
1. 亲测不能放在@Inject注解的构造函数上
2. 提供一定范围内的一个对象的唯一性。
3. 单例的范围是根Component。
这里有一个点需要说一下,不要把@Scope 想的特别神话,我最开始的时候就搞不懂这个限制是如何实现的。不过只要明白两个点就可以,一是什么对象是单例的?二是单例的范围是什么?
那么回答一下,
被@singleton 标记的@Provides方法的返回值是单例的。
单例的范围是@Singletonb标记的Component ,这里涉及到一个subcomponent的事情之后再说,接下来看一下如何实现的:
重点应该能看出来在DoubleCheck.provider();
这里是具体的实现,这里通过包装类的形式,来判断的,感觉这个地方是用来控制线程的??
因为通过测试来看,只有同一个的 Componet注入的对象才是单例的,但是这就有一个问题,其实在inject之前的,所有的初始化动作其实就都已经完成, 注入的时候实际上是调用注入工具的方法来从提供注入对象的工具中来取的,那么其实实际上的单例过程应该是在从提供注入对象工具中取对象的过程。
所以这里才是确定单例的地方,默认的时候result就是UN, 之后是枷锁,赋值,返回,这就实现了对象的单例。
那么之后就有一个问题,我们在自定义Scope的时候,真正要实现的是什么?
其实我们通过自定义的Scope所实现的根本其实就是在指定范围内的单例,跟其他任何因素都没有关系,没有生命周期之类。Scope 代表的就是单例。
网友评论