dagger2 循序漸進(jìn)學(xué)習(xí)(包會(huì))(三) 實(shí)例1,application中的應(yīng)用

文章索引
dagger2 循序漸進(jìn)學(xué)習(xí)(一)依賴注入基礎(chǔ)知識(shí)(包會(huì))
dagger2 循序漸進(jìn)學(xué)習(xí)(二)
dagger2 循序漸進(jìn)學(xué)習(xí)(三) 實(shí)例1,application中的應(yīng)用

前兩篇dagger2的文章介紹了其基本的使用方法,但其使用中還有很多重要的細(xì)節(jié)需要我們掌握,我認(rèn)為在實(shí)例中學(xué)習(xí)比羅列一大堆的理論名稱解釋要來的實(shí)在。所以接下來每篇文章主要以一個(gè)馬上能應(yīng)用起來的小實(shí)例去解釋一個(gè)個(gè)知識(shí)點(diǎn),文章在精不在多,希望我寫的文字能達(dá)到這樣的效果吧!

dagger2 知識(shí)點(diǎn)

一、@Inject

先來說下上一篇文章dagger2 循序漸進(jìn)學(xué)習(xí)(二) ,文中的activity

public class LoginActivity extends AppCompatActivity  implements ILoginContract.ILoginView{
@Inject//這里加注解
LoginPresenter presenter;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);
}

@Override
public void loginok() {

}

@Override
public void loginErro() {

}
}

文中的presenter:

public class LoginPresenter implements     ILoginContract.ILoginPresenter {
ILoginContract.ILoginView view;

@Inject//這里注解
public LoginPresenter(ILoginContract.ILoginView view) {
this.view = view;
}

@Override
public void login(String name, String pwd) {
}
}

有沒有發(fā)現(xiàn)

Paste_Image.png

presenter注入的類并沒有遵循依賴倒置的原則,就是說沒有依賴presenter的接口類,如果我們改成其接口類之后運(yùn)行就會(huì)報(bào)錯(cuò)

Paste_Image.png

那這是為什么呢,可以看出原因就在@Inject
依賴注入中第一個(gè)并且是最重要的就是 @Inject 注解。JSR-330標(biāo)準(zhǔn)中的一部分,標(biāo)記那些應(yīng)該被依賴注入框架提供的依賴。在Dagger 2中有3種不同的方式來提供依賴:

構(gòu)造器注入,

@Inject標(biāo)注在構(gòu)造器上其實(shí)有兩層意思。

①告訴Dagger2可以使用這個(gè)構(gòu)造器構(gòu)建對(duì)象。如 LoginPresenter 類構(gòu)造方法上的@Inject

②注入構(gòu)造器所需要的參數(shù)的依賴。 如 Pot 類,構(gòu)造上的Rose會(huì)被注入。又如 LoginPresenter 類構(gòu)造方法上的@Inject實(shí)現(xiàn)①的功能外,它本身還需要ILoginContract.ILoginView的依賴,此時(shí)的注入實(shí)際就在dagger2框架中 LoginModule中提供的,只是什么時(shí)候怎么提供的我們暫時(shí)不得而知

Paste_Image.png

構(gòu)造器注入的局限:如果有多個(gè)構(gòu)造器,我們只能標(biāo)注其中一個(gè),無法標(biāo)注多個(gè)。

屬性注入

如 LoginActivity 類,標(biāo)注在屬性上。被標(biāo)注的屬性不能使用 private 修飾,否則無法注入。

屬性注入也是Dagger2中使用最多的一個(gè)注入方式。
看到這里應(yīng)該明白了LoginPresenter是如何注入到LoginActivity中的了:就是1在LoginActivity屬性上標(biāo)注@Inject ,2在LoginPresenter的構(gòu)造方法上同時(shí)標(biāo)注@Inject,編譯過程中,dagger2就知道了LoginActivity的presenter屬性需要注入,接下來就去尋找哪里可以提供,其中一項(xiàng)就是就是找有沒有相應(yīng)類的構(gòu)造器用@Inject標(biāo)注的,如果有就用這個(gè)構(gòu)造器構(gòu)造后注入activity。所以當(dāng)我們把LoginActivity中的屬性改成ILoginPresenter接口類型的時(shí)候,dagger2就找不到了他的構(gòu)造器了,所以就報(bào)錯(cuò)了。

方法注入

Paste_Image.png

標(biāo)注在public方法上,Dagger2會(huì)在構(gòu)造器執(zhí)行之后立即調(diào)用這個(gè)方法。

方法注入和屬性注入基本上沒有區(qū)別, 那么什么時(shí)候應(yīng)該使用方法注入呢?

比如該依賴需要this對(duì)象的時(shí)候,使用方法注入可以提供安全的this對(duì)象,因?yàn)?strong>方法注入是在構(gòu)造器之后執(zhí)行的。

比如google mvp dagger2中,給View設(shè)置Presenter的時(shí)候可以這樣使用方法注入。

/**
 * Method injection is used here to safely reference {@code    this} after the object is created.
 * For more information, see Java Concurrency in Practice.
 */
@Inject
void setupListeners() {
 mTasksView.setPresenter(this);
 }

二、@Component

@Inject 注解是JSR-330中定義的注解,在 javax.inject 包中。
這個(gè)注解本身并沒有作用,它需要依賴于注入框架才具有意義,用來標(biāo)記需要被注入框架注入的方法,屬性,構(gòu)造。
而Dagger2則是用 Component 來完成依賴注入的, @Component 可以說是Dagger2中最重要的一個(gè)注解。
@Componentpublic interface MainActivityComponent { void inject(MainActivity activity);}

以上是定義一個(gè)Component的方式。使用接口定義,并且 @Component 注解。
命名方式推薦為: 目標(biāo)類名+Component ,在編譯后Dagger2就會(huì)為我們生成 DaggerXXXComponent 這個(gè)類,它是我們定義的 xxxComponent 的實(shí)現(xiàn),在目標(biāo)類中使用它就可以實(shí)現(xiàn)依賴注入了。
Component中一般使用兩種方式定義方法。
void inject(目標(biāo)類 obj); Dagger2會(huì)從目標(biāo)類開始查找@Inject注解,自動(dòng)生成依賴注入的代碼,調(diào)用inject可完成依賴的注入。
Object getObj(); 如: LoginPresenter getLoginPresentert();Dagger2會(huì)到LoginPresenter類中找被@Inject注解標(biāo)注的構(gòu)造器,自動(dòng)生成提供LoginPresenter依賴的代碼,這種方式一般為其他Component提供依賴。(一個(gè)Component可以依賴另一個(gè)Component,后面會(huì)說)

Component和Inject的關(guān)系如下:


Dagger2框架以Component中定義的方法作為入口,到目標(biāo)類中尋找JSR-330定義的@Inject標(biāo)注,生成一系列提供依賴的Factory類和注入依賴的Injector類。
而Component則是聯(lián)系Factory和Injector,最終完成依賴的注入。

三、@Module和@Provides

使用@Inject標(biāo)記構(gòu)造器提供依賴是有局限性的,比如說我們需要注入的對(duì)象是第三方庫提供的,我們無法在第三方庫的構(gòu)造器上加上@Inject注解。
或者,我們使用依賴倒置的時(shí)候,因?yàn)樾枰⑷氲膶?duì)象是抽象的,@Inject也無法使用,因?yàn)槌橄蟮念惒⒉荒軐?shí)例化比如咱們需要ILoginPresenter的接口類的依賴,會(huì)出現(xiàn)文中最開始的那個(gè)錯(cuò)誤;

這個(gè)時(shí)候就需要Module了。
先清除LoginPresenter中的@Inject

Paste_Image.png

并把LoginAcitivity中的依賴改成接口類型

Paste_Image.png

@Module標(biāo)記在LoginModule類上面,@Provodes標(biāo)記在方法上,表示可以通過這個(gè)方法獲取依賴。

Paste_Image.png

在@Component中指定Module


Paste_Image.png

這樣就完了,ok了。測(cè)測(cè),沒有問題;
@Module和@Provides的作用:
@Module需要和@Provide是需要一起使用的時(shí)候才具有作用的,并且@Component也需要指定了該Module的時(shí)候。

@Module是告訴Component,可以從這里獲取依賴對(duì)象。Component就會(huì)去找被@Provide標(biāo)注的方法,相當(dāng)于構(gòu)造器的@Inject,可以提供依賴。

還有一點(diǎn)要說的是,@Component可以指定多個(gè)@Module的,如果需要提供多個(gè)依賴的話。

并且Component也可以依賴其它Component存在。
如此便解決上面提到的問題;回顧一下這四個(gè)最重要的注解的用法。接下來我們研究個(gè)小實(shí)例。

實(shí)例

這個(gè)實(shí)例就是我們經(jīng)常要實(shí)現(xiàn)的application中retrofit的應(yīng)用。為了節(jié)省資源提高性能,要求我們?cè)谑褂胷etrofit時(shí)候,整個(gè)app中retrofit是單例的,然后再用他create相應(yīng)的api的接口類實(shí)例以往我們經(jīng)常會(huì)寫一大堆代碼和模式來實(shí)現(xiàn)其單例,在dagger中這一切變得簡(jiǎn)單。下面開始擼代碼:
相關(guān)的第三方庫的依賴就不寫了;
api的請(qǐng)求接口是這樣?jì)饍旱?/p>

public interface ApiService {
@GET("/users/{user}/repos")
Observable<ArrayList<String>> getRepoData(@Path("user") String user);
}

再上個(gè)module

@Module
public class ServiceModule {

@Provides
public OkHttpClient provideOkHttpClient() {
    OkHttpClient okHttpClient ;
    OkHttpClient.Builder builder= new OkHttpClient.Builder();
    okHttpClient=builder.readTimeout(60 * 1000, TimeUnit.MILLISECONDS)
            .connectTimeout(60 * 1000, TimeUnit.MILLISECONDS)
            .build();
    return okHttpClient;
}

@Provides
public Retrofit provideRetrofit(Application application, OkHttpClient okHttpClient){
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(application.getString(R.string.api_host))
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 添加Rx適配器
            .addConverterFactory(GsonConverterFactory.create()) // 添加Gson轉(zhuǎn)換器
            .client(okHttpClient)
            .build();
    return retrofit;
}
@Singleton
@Provides
protected ApiService provideGitHubService(Retrofit retrofit) {

    return retrofit.create(ApiService.class);
}

}

再來個(gè)module

@Module
public class AppModule {
private final Application application;

public AppModule(Application application) {
    this.application = application;
}

@Provides
public Application provideApplication() {
    return application;
}

}

那么再來看我們的application類中

public class App extends Application {
private  AppComponent appComponent;
@Override
public void onCreate() {
    super.onCreate();
   appComponent=
           DaggerAppComponent.builder()
           .appModule(new AppModule(this))
           .serviceModule(new ServiceModule())
           .build();
}

public  AppComponent getAppComponent() {
    return appComponent;
}
}

眼尖的同學(xué)看到了@Singleton,這個(gè)先不說,其他的不用我多說,相信前面都看懂了的同學(xué),這幾個(gè)類完全能看懂。

@Singleton顧名思義,就是單例啊,但是這個(gè)單例可不是怎么用都是單例。通過測(cè)試,我們發(fā)現(xiàn)當(dāng)重新build一個(gè)Component的時(shí)候,這個(gè)單例也是新的,所以準(zhǔn)確的說 ,它的作用只是保證依賴在@Component中是唯一的,可以理解為“局部單例”。所以在application中實(shí)例化Component,其他地方用到它的時(shí)候就需要先在application獲取appComponent進(jìn)行注操作。
通過這個(gè)方法,當(dāng)然如果也可以把他定義為static方法

public  AppComponent getAppComponent() {
return appComponent;
}

接下來我們遵循循序漸進(jìn)的原則dagger2還有部分知識(shí)點(diǎn)會(huì)在后面的文章繼續(xù)和大家分享,相信通過循序漸進(jìn)的邊學(xué)邊實(shí)踐的方式,學(xué)習(xí)起來更扎實(shí),不像一口吞個(gè)胖子樣!!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評(píng)論 6 541
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,312評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,993評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,410評(píng)論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,778評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,955評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,521評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,266評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,468評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,696評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評(píng)論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,193評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,431評(píng)論 2 378

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