dagger2 學(xué)習(xí)(三) - scope 使用

關(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 的使用方法

第一種

  1. @Scope 注解整個 Bean 對象暇屋,@inject 注解對應(yīng) Bean 對象的構(gòu)造方法
  2. @Scope 還需要在 Bean 對象注入似袁,出現(xiàn)的 Component 中標(biāo)注

第二種

  1. @Scope 配合 在Module 中使用,配合 @Provides 一起標(biāo)注
  2. @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 只需要添加到 UserModuleUserComponent

具體代碼

整個類的結(jié)構(gòu)

代碼結(jié)構(gòu)
代碼結(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.javainjectMemebers 方法在調(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)建

Dagger2 學(xué)習(xí)(三)

一家之言,僅供參考

本文代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末丛肢,一起剝皮案震驚了整個濱河市围肥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蜂怎,老刑警劉巖穆刻,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異杠步,居然都是意外死亡氢伟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門幽歼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來朵锣,“玉大人,你說我怎么就攤上這事试躏≈碛拢” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵颠蕴,是天一觀的道長泣刹。 經(jīng)常有香客問我助析,道長,這世上最難降的妖魔是什么椅您? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任外冀,我火速辦了婚禮,結(jié)果婚禮上掀泳,老公的妹妹穿的比我還像新娘雪隧。我一直安慰自己,他們只是感情好员舵,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布脑沿。 她就那樣靜靜地躺著,像睡著了一般马僻。 火紅的嫁衣襯著肌膚如雪庄拇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天韭邓,我揣著相機(jī)與錄音措近,去河邊找鬼。 笑死女淑,一個胖子當(dāng)著我的面吹牛瞭郑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鸭你,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼屈张,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了袱巨?” 一聲冷哼從身側(cè)響起袜茧,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瓣窄,沒想到半個月后笛厦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡俺夕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年裳凸,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劝贸。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡姨谷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出映九,到底是詐尸還是另有隱情梦湘,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站捌议,受9級特大地震影響哼拔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瓣颅,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一倦逐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宫补,春花似錦檬姥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贫贝,卻和暖如春荞雏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背平酿。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留悦陋,地道東北人蜈彼。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像俺驶,于是被迫代替她去往敵國和親幸逆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理暮现,服務(wù)發(fā)現(xiàn)还绘,斷路器,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法栖袋,類相關(guān)的語法拍顷,內(nèi)部類的語法,繼承相關(guān)的語法塘幅,異常的語法昔案,線程的語...
    子非魚_t_閱讀 31,581評論 18 399
  • /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home...
    光劍書架上的書閱讀 3,856評論 2 8
  • 文章作者:Tyan博客:noahsnail.com 3.5 Bean scopes When you create...
    SnailTyan閱讀 1,879評論 0 1
  • 提筆再三,我猶豫著如何措辭來表達(dá)自己對班長的敬意與欽佩电媳。 如果說金融161班是一艘航行在茫茫大海的船踏揣,班長就是掌舵...
    一只圓滾滾的大西瓜閱讀 374評論 4 1