關(guān)于Scope
Dagger 2 自帶的 Scope
只有一個 @Singleton
,其他的可以通過自定義來實現(xiàn)
1. 前言
(1) Scope
的作用研底,就是提供在當(dāng)前 Component
實例 范圍內(nèi)的單例焕数。
假設(shè) DaggerUserComponent 能夠提供 User 實例
UserComponent 被自定義的 @UserScope
標(biāo)注驴党,那就意味著
一旦一個 DaggerUserComponent 實例創(chuàng)建完成,
那么其調(diào)用 injectTo 方法这刷,進(jìn)行注入時婉烟,所有注入的 User
對象都是同一個實例
知道 DaggerUserComponent 被重新創(chuàng)建,才會提供一個不一樣的User
實例
(2) @Scope
的使用方法
第一種
-
@Scope
注解整個Bean
對象暇屋,@inject
注解對應(yīng)Bean
對象的構(gòu)造方法 -
@Scope
還需要在Bean
對象注入似袁,出現(xiàn)的Component
中標(biāo)注
第二種
-
@Scope
配合 在Module
中使用,配合@Provides
一起標(biāo)注 -
@Scope
需要在Module
出現(xiàn)的Component
中標(biāo)注
兩種方法咐刨,其實就是兩種提供實例的不同實現(xiàn)昙衅,對比前面 一二兩篇文章即可看出
第一種是最簡單注入時,加上@Scope
第二種是配合@Module
注入式定鸟,加上@Scope
2. 進(jìn)行實踐操作
(1) 整體結(jié)構(gòu)構(gòu)建
實踐的內(nèi)容主要是針對 @Scope
第二種使用方法
因此這?中間@UserScope
只需要添加到 UserModule
和 UserComponent
上
整個類的結(jié)構(gòu)
創(chuàng)建三個 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) 具體生成代碼和調(diào)用分析
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>
但是啼县,其實它的實例已經(jīng)是
DoubleCheck<User>
類型的。
跟進(jìn)這個DoubleCheck.provider()
方法
public static <T> Provider<T> provider(Provider<T> delegate) {
checkNotNull(delegate);
if (delegate instanceof DoubleCheck) {
// 如果是 DoubleCheck 的實例沸久,直接返回
return delegate;
}
// 否則創(chuàng)建一個季眷,此處的 delegate 就是 UserModule_ProvideUserFactory.create(builder.userModule)
return new DoubleCheck<T>(delegate);
}
跟進(jìn)構(gòu)造方法
private DoubleCheck(Provider<T> provider) {
assert provider != null;
this.provider = provider;
// 啥都沒有,就是賦值了一個 provider 引用
}
所以綜上卷胯,可以判斷出子刮,和之前的沒有@UserScope
注解對比,具體的實例提供者改變了窑睁,不是生成UserModule_ProvideUserFactory
對象了,變成了DoubleCheck<User>
對象,其內(nèi)部持有一個 UserModule_ProvideUserFactory
的引用巨缘。
b.整體調(diào)用鏈
DaggerUserComponent.injectTo
-> ClassARoomActivity_MembersInjector.injectMembers()
-> mUserProvider.get()
-> DoubleCheck<User>.get()
下面進(jìn)行具體分析
-
DaggerUserComponent.injectTo
->ClassARoomActivity_MembersInjector.injectMembers()
部分因此其調(diào)用的實例也有了對應(yīng)的改變,對應(yīng)的
xxxInjector.java
的injectMemebers
方法在調(diào)用時啸罢,會調(diào)用不同的實例該部分代碼和之前并無區(qū)別,主要是運行時,實例的區(qū)別
@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();// 注意該部分會調(diào)用不同的實例對應(yīng)的方法 }
-
mUserProvider.get()
->DoubleCheck<User>.get()
未加上
@UserScop
時,實例是UserModule_ProvideUserFactory
調(diào)用的是
UserModule_ProvideUserFactory.java
中的方法吓著,如下@Override public User get() { return Preconditions.checkNotNull( module.provideUser(), "Cannot return null from a non-@Nullable @Provides method"); }
加上
@UserScop
時,實例是DoubleCheck<User>
調(diào)用的是
DoubleCheck<T>
中的方法送挑,如下,該部分也是實現(xiàn)Scope
功能重要的一部分public T get() { Object result = instance; if (result == UNINITIALIZED) {// 如果該對象從來沒有初始化暖眼,那就初始化一次 synchronized (this) { result = instance;// 獲取最新實例惕耕,防止線程之間同時修改 if (result == UNINITIALIZED) { result = provider.get();// 此處依舊調(diào)用了 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; // 初始化一次以后,該對象對應(yīng)的 Provider 在當(dāng)前 Scope 中其實已經(jīng)沒有意義了诫肠, // 所以直接置為空司澎,方便 GC 回收 } } } return (T) result;// 返回結(jié)果 }
>注意,Provider 的置空 > >此處的置空不會影響數(shù)據(jù)的獲取栋豫,該 `provider` 的引用就是下面方法中的 `UserModule_ProvideUserFactory.create(builder.userModule)` 對 > >```java >this.provideUserProvider = DoubleCheck.provider(UserModule_ProvideUserFactory.create(builder.userModule)); >```
3. 總結(jié)
總結(jié):
@UserScope
作用于 Component
生命周期內(nèi)
限制了被標(biāo)注的實例提供者挤安,只會實例化該對象一次,之后會拋棄對應(yīng)的 Provider
丧鸯,然后永遠(yuǎn)獲取之前創(chuàng)建的User
@UserScope @Provides provideUser()
==>UserModule_ProviderUserFactory
此處拋棄的就是
UserModule_ProviderUserFactory
的實例
只有當(dāng)實例化的 Component
對象被重新構(gòu)建蛤铜,被標(biāo)注的實例提供者才會重新創(chuàng)建
一家之言,僅供參考