dagger2入門(mén)指南

dagger2入門(mén)指南

配置Dagger2

參考Dagger2 Wiki笋轨,在Gradle中添加以下依賴


dependencies {
  
      provided 'javax.annotation:javax.annotation-api:1.2'
  
      compile 'com.google.dagger:dagger:2.0.2'
  
      apt 'com.google.dagger:dagger-compiler:2.0.2'
}

apt是一個(gè)Gradle插件秆剪,協(xié)助Android Studio 處理Annotation Processors,所以在Gradle中還必須添加以下內(nèi)容(關(guān)于Android-apt更多內(nèi)容參考)


dependencies {
     
      classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
 
}

 apply plugin: 'com.neenbedankt.android-apt'

開(kāi)始使用

Dagger2是實(shí)現(xiàn)依賴注入的一種手段爵政,關(guān)于依賴注入仅讽,這里就不多介紹,想了解的可以參考, Dagger2中需要使用注解來(lái)完成依賴注入钾挟,我們來(lái)一個(gè)個(gè)介紹這些注解

@Inject

我們可以使用@Inject這個(gè)注解來(lái)標(biāo)注目標(biāo)類中所依賴的其他類洁灵,也可以用來(lái)標(biāo)注所依賴的其他類的構(gòu)造函數(shù)。舉個(gè)例子

  
public class Human{
     
   @Inject 
   Father father;
  
}
  
  
public class Father{
     
    @Inject
     
    public Father(){  //如果標(biāo)注有參數(shù)的構(gòu)造方法掺出,在調(diào)用構(gòu)造方法前會(huì)去獲取參數(shù)對(duì)應(yīng)的對(duì)象
     
    }
  
}


當(dāng)Human需要通過(guò)@Inject注入Father這個(gè)類的時(shí)候徽千,會(huì)先調(diào)用Father中標(biāo)注的構(gòu)造函數(shù),生成相應(yīng)的對(duì)象汤锨。這樣HumanFather之間就有了一種無(wú)形的聯(lián)系罐栈,但是僅僅這樣還不夠,我們還需要用到Component來(lái)使他們連接起來(lái)

@Component


@Component的作用就是連接目標(biāo)類和目標(biāo)類依賴實(shí)例(可以通過(guò)上面說(shuō)的@Inject標(biāo)注構(gòu)造函數(shù)也可以通過(guò)@Module來(lái)產(chǎn)生)泥畅。那Component是怎么工作的呢荠诬?

  • 查找目標(biāo)類中用@Inject標(biāo)注的屬性

  • 查找對(duì)應(yīng)屬性依賴實(shí)例

  • 將依賴實(shí)例進(jìn)行賦值

目標(biāo)類需要初始化自己依賴的其他類還需要調(diào)用Component的inject(Object object)方法開(kāi)始注入

@Singleton @Component(modules = { ApplicationModule.class},dependencies={xxxComponent.class})
public interface ApplicationComponent {

  Context getContext();

  void inject(MyApplication mApplication);
}

比如在MyApplication中需要注入其他類琅翻,則需要在MyApplication中調(diào)用ApplicationComponentinject方法開(kāi)始注入。

  • modules對(duì)應(yīng)的就是提供依賴的Module類柑贞,可以有多個(gè)
  • dependencies表示該Component還依賴其他Component
  • @Singleton是一種Scope注解方椎,下面會(huì)說(shuō)到

@Module

介紹@Inject的時(shí)候我們說(shuō)過(guò),可以通過(guò)@Inject標(biāo)注構(gòu)造函數(shù)生成對(duì)應(yīng)的對(duì)象钧嘶,但是如果是第三方類庫(kù)棠众,我們無(wú)法添加@Inject注解的時(shí)候該怎么辦,這時(shí)候就需要用到@Module了有决。舉個(gè)列子

    
@Module
    
public class Module{
          
    //A是第三方類庫(kù)中的一個(gè)類
          
    @Provides
 A provideA(){
               
           return A();
          
    }
    
}

  • 通過(guò)provideA()這個(gè)方法我們就可以生成一個(gè)A的實(shí)例闸拿,目標(biāo)類中可以通過(guò)@Inject來(lái)注入

  • @provides標(biāo)注的方法直接返回以創(chuàng)建或者新創(chuàng)建的對(duì)象,只在Module中使用

  • Component會(huì)首先從Module中查找需要注入的實(shí)例书幕,如果找到了新荤,則停止,如果沒(méi)有找到則是繼續(xù)從Inject標(biāo)注的構(gòu)造函數(shù)查找

@Qualifier

通過(guò)上面我們知道台汇,創(chuàng)建類的實(shí)例有兩種方式苛骨,這兩個(gè)方式有先后之分,但是如果一個(gè)類在同一方式下有多個(gè)創(chuàng)建類的方法的時(shí)候苟呐,Component會(huì)選取哪個(gè)方法來(lái)創(chuàng)建這個(gè)類的實(shí)例呢痒芝?舉個(gè)例子

    @Module
    public class Module{
          
          @Provides
          A provideA(){
            return A();
          }
          
          @provides
          A provideOtherA(){
                 return A();
          }
    }

如果我們按照上面這樣寫(xiě),Dagger2在編譯的時(shí)候就會(huì)報(bào)錯(cuò)牵素,那么我們改如何解決呢严衬?這時(shí)候就需要用到@Qualifier了,我們可以用這個(gè)注解給不同的創(chuàng)建實(shí)例的方法進(jìn)行標(biāo)識(shí)并加以區(qū)分笆呆。

    @Module
    public class Module{
          
          @Named("firstA")
          @Provides
          A provideFirstA(){
               return A();
          }

          @Named("secondA")
          @provides
          A provideSecondA(){
                 return A();
          }
    }

@Named是Dagger2對(duì)于@Qualifier一個(gè)默認(rèn)實(shí)現(xiàn)瞳步,我們也可以自定義,比如@ForApplication@ForAcitivity來(lái)標(biāo)識(shí)不同的Context

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {

    /** The name. */
    String value() default "";
}

這樣腰奋,通過(guò)@Named我們就可以區(qū)分不同的實(shí)例了

    public class Human{
       @Inject
       @Named("firstA")
       A firstA;

       @Named("secondA")
       @provides
       A secondA;
    }

@Scope

Scope是一個(gè)注解作用域单起,通過(guò)自定義注解限定對(duì)象的作用范圍。通過(guò)這個(gè)注解能夠解決不同對(duì)象生命周期不一致的問(wèn)題劣坊,比如Application,ToastHelper等存在于應(yīng)用的整個(gè)生命周期嘀倒,Adapter,Presenter等則隨著Activity的銷毀而銷毀。我們可以通過(guò)自定義不同的Scope來(lái)區(qū)分局冰。舉個(gè)例子

@Scope
@Documented
@Retention(RUNTIME)
public @interface PerApp{}
@PerApp @Component(modules = { ApplicationModule.class})
public interface ApplicationComponent {

  Context getContext();

  void inject(MyApplication mApplication);
}
@Module 
public class ApplicationModule {

  private final Context context;

  public ApplicationModule(Context context) {
    this.context = context;
  }

  @Provides @PerApp public Context provideApplicationContext() {
    return context.getApplicationContext();
  }
}

我們?cè)?code>ApplicationModule中定義了創(chuàng)建Context實(shí)例的方法测蘑,在ApplicationComponent中管理ApplicationModule,因?yàn)?code>ApplicationComponent只有在Application中實(shí)例化一次康二,所以Context的生命周期也就和Application一樣了碳胳,也就是Dagger并不會(huì)幫你管理生命周期,只能自己來(lái)控制沫勿。那么PerApp這個(gè)注解有什么用呢挨约?

  • 更好的管理ComponentModule之間的匹配關(guān)系味混,Dagger2在編譯的時(shí)候會(huì)檢查Component管理的Module,若發(fā)現(xiàn)Component所標(biāo)注的自定義Scope注解與Module中不一樣诫惭,就會(huì)報(bào)錯(cuò)翁锡。
  • 提高可讀性,通過(guò)PerApp就知道是在整個(gè)Application有小范圍內(nèi)

注意點(diǎn):

  • 一個(gè)Module中只能存在一種Scope
  • Scope標(biāo)注的Component和所依賴的ComponentScope不能一樣

實(shí)例講解

創(chuàng)建ApplicationComponent

@PerApp
@Component(modules = { ApplicationModule.class })
public interface ApplicationComponent {
  Context getContext();

  ToastUtils getToastUtils();
}

ApplicationComponent是一個(gè)全局的Component,負(fù)責(zé)管理整個(gè)App的全局類實(shí)例,Context getContext();ToastUtils getToastUtils();是將ContextToastUtils暴露給子Component夕土。

創(chuàng)建ApplicationModule

@Module 
public class ApplicationModule {
  private final MyApplication myApplication;

  public ApplicationModule(MyApplication myApplication) {
    this.myApplication = myApplication;
  }

  @PerApp @Provides Context provideContext() {
    return myApplication.getApplicationContext();
  }

  @PerApp @Provides ToastUtils provideToastUtils(Context mContext) {
    return new ToastUtils(mContext);
  }
}

ApplicationModule生成全局ContextToastUtils實(shí)例

在Application中創(chuàng)建ApplicationComponent實(shí)例

public class MyApplication extends Application {
  private ApplicationComponent mApplicationComponent;

  @Override public void onCreate() {
    super.onCreate();
    mApplicationComponent =
        DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(this)).build();
  }

  public ApplicationComponent getApplicationComponent() {
    return mApplicationComponent;
  }
}

DaggerApplicationComponent這個(gè)是有Dagger2生成的類馆衔,因?yàn)?code>ApplicationComponent只初始化一次,所以注入的類都是單例的怨绣,這就是Dagger2真正創(chuàng)建單例的方法角溃。

劃分Component

一個(gè)應(yīng)用應(yīng)該包含一個(gè)全局的Component,負(fù)責(zé)管理整個(gè)全局類的實(shí)例篮撑,其他Componet建議按照頁(yè)面來(lái)劃分减细。

@PerActivity 
@Component(dependencies = ApplicationComponent.class, modules = {
    MainModule.class, ActivityModule.class
}) 
public interface MainComponent {

  void inject(MainActivity mActivity);
}
@Module
public class MainModule {

  @PerActivity @Provides GetUser getUser() {
    return new GetUser();
  }
}
@PerActivity
@Component(modules = { ActivityModule.class })
public interface ActivityComponent {

  Activity getActivity();

}
@Module 
public class ActivityModule {
  private final Activity mActivity;

  public ActivityModule(Activity mActivity) {
    this.mActivity = mActivity;
  }

  @Provides @PerActivity Activity provideActivity() {
    return mActivity;
  }
}

上面是Main這個(gè)頁(yè)面的劃分

DEMO

demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市咽扇,隨后出現(xiàn)的幾起案子邪财,更是在濱河造成了極大的恐慌陕壹,老刑警劉巖质欲,帶你破解...
    沈念sama閱讀 211,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異糠馆,居然都是意外死亡嘶伟,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)又碌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)九昧,“玉大人,你說(shuō)我怎么就攤上這事毕匀≈ィ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,435評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵皂岔,是天一觀的道長(zhǎng)蹋笼。 經(jīng)常有香客問(wèn)我,道長(zhǎng)躁垛,這世上最難降的妖魔是什么剖毯? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,509評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮教馆,結(jié)果婚禮上逊谋,老公的妹妹穿的比我還像新娘。我一直安慰自己土铺,他們只是感情好胶滋,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布板鬓。 她就那樣靜靜地躺著,像睡著了一般镀钓。 火紅的嫁衣襯著肌膚如雪穗熬。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,837評(píng)論 1 290
  • 那天丁溅,我揣著相機(jī)與錄音唤蔗,去河邊找鬼。 笑死窟赏,一個(gè)胖子當(dāng)著我的面吹牛妓柜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播涯穷,決...
    沈念sama閱讀 38,987評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼棍掐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了拷况?” 一聲冷哼從身側(cè)響起作煌,我...
    開(kāi)封第一講書(shū)人閱讀 37,730評(píng)論 0 267
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赚瘦,沒(méi)想到半個(gè)月后粟誓,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,194評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡起意,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評(píng)論 2 327
  • 正文 我和宋清朗相戀三年鹰服,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片揽咕。...
    茶點(diǎn)故事閱讀 38,664評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡悲酷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亲善,到底是詐尸還是另有隱情设易,我是刑警寧澤,帶...
    沈念sama閱讀 34,334評(píng)論 4 330
  • 正文 年R本政府宣布蛹头,位于F島的核電站顿肺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏掘而。R本人自食惡果不足惜挟冠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望袍睡。 院中可真熱鬧知染,春花似錦、人聲如沸斑胜。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,764評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至掺炭,卻和暖如春辫诅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背涧狮。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,997評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工炕矮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人者冤。 一個(gè)月前我還...
    沈念sama閱讀 46,389評(píng)論 2 360
  • 正文 我出身青樓肤视,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親涉枫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子邢滑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評(píng)論 2 349

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