关于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
但是,其实它的实例已经是
DoubleCheck
类型的。
跟进这个DoubleCheck.provider()
方法
public static Provider provider(Provider delegate) {
checkNotNull(delegate);
if (delegate instanceof DoubleCheck) {
// 如果是 DoubleCheck 的实例,直接返回
return delegate;
}
// 否则创建一个,此处的 delegate 就是 UserModule_ProvideUserFactory.create(builder.userModule)
return new DoubleCheck(delegate);
}
跟进构造方法
private DoubleCheck(Provider provider) {
assert provider != null;
this.provider = provider;
// 啥都没有,就是赋值了一个 provider 引用
}
所以综上,可以判断出,和之前的没有@UserScope
注解对比,具体的实例提供者改变了,不是生成UserModule_ProvideUserFactory
对象了,变成了DoubleCheck
对象,其内部持有一个 UserModule_ProvideUserFactory
的引用。
b.整体调用链
DaggerUserComponent.injectTo
-> ClassARoomActivity_MembersInjector.injectMembers()
-> mUserProvider.get()
-> DoubleCheck
下面进行具体分析
-
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
.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
调用的是
DoubleCheck
中的方法,如下,该部分也是实现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
对象被重新构建,被标注的实例提供者才会重新创建
一家之言,仅供参考
本文代码