关于Scope
Dagger 2 自带的 Scope 只有一个 @Singleton ,其他的可以通过自定义来实现
1. 前言
(1) Scope 的作用,就是提供在当前 Component 实例 范围内的单例。
假设 DaggerUserComponent 能够提供 User 实例
UserComponent 被自定义的 @UserScope 标注,那就意味着
一旦一个 DaggerUserComponent 实例创建完成,
那么其调用 injectTo 方法,进行注入时,所有注入的 User 对象都是同一个实例
知道 DaggerUserComponent 被重新创建,才会提供一个不一样的User实例
(2) @Scope 的使用方法
第一种
-
@Scope注解整个Bean对象,@inject注解对应Bean对象的构造方法 -
@Scope还需要在Bean对象注入,出现的Component中标注
第二种
-
@Scope配合 在Module中使用,配合@Provides一起标注 -
@Scope需要在Module出现的Component中标注
两种方法,其实就是两种提供实例的不同实现,对比前面 一二两篇文章即可看出
第一种是最简单注入时,加上@Scope
第二种是配合@Module 注入式,加上@Scope
2. 进行实践操作
(1) 整体结构构建
实践的内容主要是针对 @Scope 第二种使用方法
因此这�中间@UserScope 只需要添加到 UserModule 和 UserComponent 上
整个类的结构

创建三个 Activity 分别用于显示 User 实例
下面贴出部分代码
自定义 UserScope.java
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface UserScope {
}
User.java
public class User {
...//纯 Bean 对象,无任何特殊
}
UserComponent.java
@UserScope// 绑定 UserScope
@Component(modules = {UserModule.class})
public interface UserComponent {
void injectTo(ClassARoomActivity classARoomActivity);
void injectTo(ClassBRoomActivity classBRoomActivity);
}
UserModule.java
@Module
public class UserModule {
...
@UserScope// 绑定 UserScope
@Provides
User provideUser(){
return new User();
}
}
App.java
...
static UserComponent sUserComponent;
...
public static UserComponent getUserComponent(){// 获取 DaggerUserComponent 对象
if (sUserComponent == null){
sUserComponent = DaggerUserComponent.builder().userModule(new UserModule())
.build();
}
return sUserComponent;
}
public static void releaseUserComponent(){ // 清空 DaggerUserComponent 对象
sUserComponent = null;
}
...
(2) 具体生成代码和调用分析
a. 代码生成部分分析
DaggerUserComponent.java 部分代码变化
未加上 @UserScope 时,provideUserProvider 的生成
this.provideUserProvider = UserModule_ProvideUserFactory.create(builder.userModule);
加上 @UserScope 后,provideUserProvider 的生成
this.provideUserProvider =
DoubleCheck.provider(UserModule_ProvideUserFactory.create(builder.userModule));
注意,虽然此处的
provideUserProvider依然是Provider<User>但是,其实它的实例已经是
DoubleCheck<User>类型的。
跟进这个DoubleCheck.provider() 方法
public static <T> Provider<T> provider(Provider<T> delegate) {
checkNotNull(delegate);
if (delegate instanceof DoubleCheck) {
// 如果是 DoubleCheck 的实例,直接返回
return delegate;
}
// 否则创建一个,此处的 delegate 就是 UserModule_ProvideUserFactory.create(builder.userModule)
return new DoubleCheck<T>(delegate);
}
跟进构造方法
private DoubleCheck(Provider<T> provider) {
assert provider != null;
this.provider = provider;
// 啥都没有,就是赋值了一个 provider 引用
}
所以综上,可以判断出,和之前的没有@UserScope 注解对比,具体的实例提供者改变了,不是生成UserModule_ProvideUserFactory 对象了,变成了DoubleCheck<User> 对象,其内部持有一个 UserModule_ProvideUserFactory 的引用。
b.整体调用链
DaggerUserComponent.injectTo -> ClassARoomActivity_MembersInjector.injectMembers() -> mUserProvider.get() -> DoubleCheck<User>.get()
下面进行具体分析
-
DaggerUserComponent.injectTo->ClassARoomActivity_MembersInjector.injectMembers()部分因此其调用的实例也有了对应的改变,对应的
xxxInjector.java的injectMemebers方法在调用时,会调用不同的实例该部分代码和之前并无区别,主要是运行时,实例的区别
@Override public void injectTo(ClassARoomActivity classARoomActivity) { classARoomActivityMembersInjector.injectMembers(classARoomActivity); }@Override public void injectMembers(ClassARoomActivity instance) { if (instance == null) { throw new NullPointerException("Cannot inject members into a null reference"); } instance.mUser = mUserProvider.get();// 注意该部分会调用不同的实例对应的方法 } -
mUserProvider.get()->DoubleCheck<User>.get()未加上
@UserScop时,实例是UserModule_ProvideUserFactory调用的是
UserModule_ProvideUserFactory.java中的方法,如下@Override public User get() { return Preconditions.checkNotNull( module.provideUser(), "Cannot return null from a non-@Nullable @Provides method"); }加上
@UserScop时,实例是DoubleCheck<User>调用的是
DoubleCheck<T>中的方法,如下,该部分也是实现Scope功能重要的一部分public T get() { Object result = instance; if (result == UNINITIALIZED) {// 如果该对象从来没有初始化,那就初始化一次 synchronized (this) { result = instance;// 获取最新实例,防止线程之间同时修改 if (result == UNINITIALIZED) { result = provider.get();// 此处依旧调用了 UserModule_ProvideUserFactory.get() 方法 Object currentInstance = instance; if (currentInstance != UNINITIALIZED && currentInstance != result) { throw new IllegalStateException("Scoped provider was invoked recursively returning " + "different results: " + currentInstance + " & " + result); } instance = result; // 赋值最新的值 provider = null; // 初始化一次以后,该对象对应的 Provider 在当前 Scope 中其实已经没有意义了, // 所以直接置为空,方便 GC 回收 } } } return (T) result;// 返回结果 }>注意,Provider 的置空 > >此处的置空不会影响数据的获取,该 `provider` 的引用就是下面方法中的 `UserModule_ProvideUserFactory.create(builder.userModule)` 对 > >```java >this.provideUserProvider = DoubleCheck.provider(UserModule_ProvideUserFactory.create(builder.userModule)); >```
3. 总结
总结:
@UserScope 作用于 Component 生命周期内
限制了被标注的实例提供者,只会实例化该对象一次,之后会抛弃对应的 Provider ,然后永远获取之前创建的User
@UserScope @Provides provideUser()==>UserModule_ProviderUserFactory此处抛弃的就是
UserModule_ProviderUserFactory的实例
只有当实例化的 Component 对象被重新构建,被标注的实例提供者才会重新创建

一家之言,仅供参考
