關于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
對象被重新構建,被標注的實例提供者才會重新創建
一家之言,僅供參考