Dagger2 | 三凯傲、進(jìn)階 - @Provides

Dagger2 中的 @Provides 是 @Inject 的替代方案。當(dāng)需要提供實(shí)例時(shí)嗦篱,由于 @Inject 注解在構(gòu)造函數(shù)上泣洞,因此無(wú)法提供第三方庫(kù)的實(shí)例,而 @Provides 則注解在方法上默色,可以通過(guò)方法返回第三方庫(kù)實(shí)例球凰。

API 描述:

Annotates methods of a @Module to create a provider method binding. The method's return type is bound to its returned value. The @Component implementation will pass dependencies to the method as parameters.

簡(jiǎn)單翻譯:

@Module 注解在模塊方法上,用來(lái)創(chuàng)建提供者方法綁定腿宰。模塊方法的返回類(lèi)型綁定到它的返回值呕诉。 @Component 的實(shí)現(xiàn)是將依賴(lài)項(xiàng)作為參數(shù)傳遞到模塊方法。

注意吃度,默認(rèn)情況下甩挫,Dagger2 禁止注入 null 值,調(diào)用 @Provides 注解的方法如果返回 null 值椿每,將立即拋出 NullPointerException 異常伊者。通過(guò) @Nullable 可以允許 null 值,但注入字段也必須用 @Nullable 注解间护,否則將編譯失敗亦渗。

3.1 進(jìn)階實(shí)戰(zhàn)

根據(jù) API 描述,我們先嘗試提供 Account 類(lèi)的實(shí)例汁尺,之后再用第三方庫(kù)提供實(shí)例法精。

3.1.1 賬戶(hù)模塊

查看 @Module 的 API 描述:

Annotates a class that contributes to the object graph.

簡(jiǎn)單翻譯:

注解在類(lèi)上,以便貢獻(xiàn)對(duì)象圖譜痴突。

創(chuàng)建 AccoutModule 類(lèi)搂蜓,添加 provideAccount 方法:

@Module
final class AccountModule {

    @Provides
    Account provideAccount() {
        return new Account();
    }
}

注意,你可以有任意命名辽装,但約定俗成的是帮碰,@Providers 注解的方法以 provide 作為前綴。

查看編譯生成的內(nèi)容:

public final class AccountModule_ProvideAccountFactory implements Factory<Account> {
  // ...

  @Override
  public Account get() {
    return provideAccount(module);
  }

  // ...

  public static Account provideAccount(AccountModule instance) {
    return Preconditions.checkNotNull(instance.provideAccount(), "Cannot return null from a non-@Nullable @Provides method");
  }
}

恰好印證 Factory 接口的 API 描述拾积,即可以通過(guò) @Provides 注解的方法執(zhí)行綁定邏輯殉挽。

3.1.2 組件和模塊

回憶一下 @Component 的 API 描述:它可以從一組 @Module 集合中生成完整的依賴(lài)注入實(shí)現(xiàn)丰涉。

所以我們將模塊交給組件管理:

@Component(modules = AccountModule.class)
public interface ActivityComponent {
// ...
}

編譯后的內(nèi)容:

public final class DaggerActivityComponent implements ActivityComponent {
  // ...

  @Override
  public Account account() {
    return AccountModule_ProvideAccountFactory.provideAccount(accountModule);}

  @Override
  public void inject(MainActivity activity) {
    injectMainActivity(activity);}

  private MainActivity injectMainActivity(MainActivity instance) {
    MainActivity_MembersInjector.injectAccount(instance, AccountModule_ProvideAccountFactory.provideAccount(accountModule));
    return instance;
  }

  // ...
}

之前直接 new 實(shí)例的代碼消失,轉(zhuǎn)而調(diào)用 provideAccount 方法執(zhí)行注入此再。

我們注意到 ActivityComponent.Builder 類(lèi)的 build 方法:

    public ActivityComponent build() {
      if (accountModule == null) {
        this.accountModule = new AccountModule();
      }
      return new DaggerActivityComponent(accountModule);
    }

默認(rèn)情況下,模塊實(shí)例由建造者直接 new 出來(lái)玲销。

思考:如果模塊需要用 Context 進(jìn)行初始化输拇,該如何處理?

3.1.3 簡(jiǎn)單測(cè)試

我們依然對(duì)構(gòu)造函數(shù)上的 @Inject 抱有敵意贤斜,移除它之后策吠,再編譯一下:

消失的 Account 工廠類(lèi)

Account_Factory 類(lèi)消失不見(jiàn),現(xiàn)在 Account 是 POJO 類(lèi)瘩绒。

3.1.4 第三方庫(kù)

我們用真正的第三方庫(kù)來(lái)提供依賴(lài)猴抹。

聲明依賴(lài)

在項(xiàng)目的 build.gradle 文件中,引入 jitpack.io 庫(kù):

allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://jitpack.io' }
    }
}

在 app 模塊的 build.gradle 文件中锁荔,添加內(nèi)容:

dependencies {
    // ...
    implementation 'com.github.mrzhqiang:security:v1.0'
}

說(shuō)明一下蟀给,這個(gè)框架是從 spring-security-crypto 扒到 Android 上來(lái),用于信息的摘要加密處理阳堕。

為了運(yùn)行它跋理,我們還需要在 JDK1.8 版本上編譯,所以修改 app 模塊中的 build.gradle 文件:

android {
    // ...
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

提供依賴(lài)

在賬戶(hù)模塊下提供依賴(lài):

@Module 
final class AccountModule {

    @Provides
    Account provideAccount() {
        return new Account();
    }

    @Provides
    PasswordEncoder providePasswordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
}

編譯后恬总,生成新的類(lèi):

密碼編碼的提供者工廠

注入依賴(lài)

注入到 MainActivity 類(lèi)前普,對(duì)密碼進(jìn)行加密處理:

public class MainActivity extends AppCompatActivity {

    @Inject
    Account account;
    @Inject
    PasswordEncoder passwordEncoder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerActivityComponent.create().inject(this);

        TextView contentText = findViewById(R.id.content_text);
        String content = String.format("username: %s, password: %s, encodePassword: %s",
            account.getUsername(),
            account.getPassword(),
            passwordEncoder.encode(account.getPassword()));
        contentText.setText(content);
    }
}

3.2 運(yùn)行

現(xiàn)在我們來(lái)運(yùn)行一下,看看效果:

成功注入第三方庫(kù)

即使是 123456 這樣的密碼壹堰,經(jīng)過(guò)加密處理后拭卿,也是普通暴力破解望而卻步的長(zhǎng)度和復(fù)雜度。

3.3 總結(jié)

@Provides 注解在提供者方法上贱纠,用來(lái)提供第三方庫(kù)依賴(lài)峻厚。

不僅如此,當(dāng)我們提取通用類(lèi)到公共模塊中谆焊,又希望公共模塊保持純潔目木,則可以通過(guò) @Provides 提供其依賴(lài)。更多情況下懊渡,創(chuàng)建實(shí)例之后還需要執(zhí)行初始化操作刽射,為此使用 @Provides@Inject 更靈活。

下一章剃执,討論 @Singleton誓禁,它可以幫助我們實(shí)現(xiàn)最佳單例模式。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末肾档,一起剝皮案震驚了整個(gè)濱河市摹恰,隨后出現(xiàn)的幾起案子辫继,更是在濱河造成了極大的恐慌,老刑警劉巖俗慈,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姑宽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡闺阱,警方通過(guò)查閱死者的電腦和手機(jī)炮车,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)酣溃,“玉大人瘦穆,你說(shuō)我怎么就攤上這事∩尥悖” “怎么了扛或?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)碘饼。 經(jīng)常有香客問(wèn)我熙兔,道長(zhǎng),這世上最難降的妖魔是什么艾恼? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任黔姜,我火速辦了婚禮,結(jié)果婚禮上蒂萎,老公的妹妹穿的比我還像新娘秆吵。我一直安慰自己,他們只是感情好五慈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布纳寂。 她就那樣靜靜地躺著,像睡著了一般泻拦。 火紅的嫁衣襯著肌膚如雪毙芜。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天争拐,我揣著相機(jī)與錄音腋粥,去河邊找鬼。 笑死架曹,一個(gè)胖子當(dāng)著我的面吹牛隘冲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播绑雄,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼展辞,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了万牺?” 一聲冷哼從身側(cè)響起罗珍,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤洽腺,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后覆旱,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蘸朋,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年扣唱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了藕坯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡画舌,死狀恐怖堕担,靈堂內(nèi)的尸體忽然破棺而出已慢,到底是詐尸還是另有隱情曲聂,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布佑惠,位于F島的核電站朋腋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏膜楷。R本人自食惡果不足惜旭咽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赌厅。 院中可真熱鬧穷绵,春花似錦、人聲如沸特愿。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)揍障。三九已至目养,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間毒嫡,已是汗流浹背癌蚁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留兜畸,地道東北人努释。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像咬摇,于是被迫代替她去往敵國(guó)和親洽洁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355