dagger2使用方法簡(jiǎn)明講解

現(xiàn)在的公司項(xiàng)目用到了Dagger2,之前只是稍微了解一些巴碗,沒有用過朴爬,然后查了查資料,整理如下橡淆,方便快速上手

四個(gè)基本注解

  1. @Inject 主要有兩個(gè)作用召噩,一個(gè)是使用在構(gòu)造函數(shù)上,通過標(biāo)記構(gòu)造函數(shù)讓Dagger2來使用(Dagger2通過Inject標(biāo)記可以在需要這個(gè)類實(shí)例的時(shí)候來找到這個(gè)構(gòu)造函數(shù)并把相關(guān)實(shí)例new出來)從而提供依賴明垢,另一個(gè)作用就是標(biāo)記在需要依賴的變量讓Dagger2為其提供依賴蚣常。

    @Inject注解的字段不能是private和protected的

  2. @Module 用Module標(biāo)注的類是專門用來提供依賴的。有的人可能有些疑惑痊银,看了上面的@Inject抵蚊,需要在構(gòu)造函數(shù)上標(biāo)記才能提供依賴,那么如果我們需要提供的類構(gòu)造函數(shù)無(wú)法修改怎么辦,比如一些jar包里的類贞绳,我們無(wú)法修改源碼谷醉。這時(shí)候就需要使用Module了。Module可以給不能修改源碼的類提供依賴冈闭,當(dāng)然俱尼,能用Inject標(biāo)注的通過Module也可以提供依賴。

    這里需要注意萎攒,Module和Inject這兩個(gè)注解還是有區(qū)別的遇八,@Inject使用在構(gòu)造函數(shù)上的時(shí)候,這個(gè)構(gòu)造函數(shù)有沒有參數(shù)都可以耍休,如果有參數(shù)的話這個(gè)構(gòu)造函數(shù)也需要有其他Module或者@Inject構(gòu)造函數(shù)提供實(shí)例刃永,適合在提供該類自己的時(shí)候使用。但是如果用@Module的話羊精,@Module注解的這個(gè)類需要有默認(rèn)無(wú)參構(gòu)造函數(shù)(顯示隱式都可以)斯够,否則會(huì)報(bào)“”xxx must be set”。如果沒有默認(rèn)無(wú)參構(gòu)造函數(shù)喧锦,就需要手動(dòng)把這個(gè)Module的實(shí)例傳入Component读规,一般在MVP模式里使用該方式,用來提供Activity實(shí)例給Presenter實(shí)例燃少。

    所以束亏,如果該類只需要提供自己,建議直接使用@Inject函數(shù)阵具,如果是用來提供其他類的實(shí)例枪汪,建議使用@Module的方式。

  3. @Provides 用Provides來標(biāo)注一個(gè)方法怔昨,該方法可以在需要提供依賴時(shí)被調(diào)用,從而把預(yù)先提供好的對(duì)象當(dāng)做依賴給標(biāo)注了@Inject的變量賦值宿稀。provides用于標(biāo)注Module里的方法趁舀。

    類似@Provides的還有一個(gè)注解叫@Binds,和@Provides的區(qū)別是@Binds只能修飾抽象方法祝沸,假如有2個(gè)類接口A和它的子類AImpl矮烹,你需要這個(gè)方法的返回值為A,以便實(shí)現(xiàn)面向接口編程罩锐,雖然@Provides也能實(shí)現(xiàn)奉狈,但是用@Binds明顯意義更加清晰

  4. @Component 用來標(biāo)注接口,被標(biāo)注了Component的接口在編譯時(shí)會(huì)產(chǎn)生相應(yīng)的類的實(shí)例來作為提供依賴方和需要依賴方之間的橋梁涩惑,把相關(guān)依賴注入到其中仁期。

四個(gè)擴(kuò)展注解

  1. @Qulifier 這里有個(gè)概念,叫依賴迷失,就是在Module注解的類里跛蛋,有2個(gè)Provides都提供某個(gè)類的實(shí)例熬的,這時(shí)候不用@Qulifier注解的話Component會(huì)不知道用哪個(gè)實(shí)例,這時(shí)候就要使用@Qulifier赊级,下面直接提供代碼

    @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    public @interface A {}
    
    @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    public @interface B {}
    
    @Module
    public class SimpleModule {
    
     @Provides
     @A
     Cooker provideCookerA(){
         return new Cooker("James","Espresso");
     }
    
     @Provides
     @B
     Cooker provideCookerB(){
         return new Cooker("Karry","Machiato");
     }
    }
    
    public class ComplexMaker implements CoffeeMaker {
        Cooker cookerA;
        Cooker cookerB;
    
        @Inject
        public ComplexMaker(@A Cooker cookerA,@B Cooker cookerB){
            this.cookerA = cookerA;
            this.cookerB = cookerB;
        }
    }
    
  2. @Named@Qulifier一樣押框,并且@Named就是繼承@Qulifier的,而且用起來比@Qulifier方便理逊,示例代碼如下:

    @Module
    public class MainModule {
    
        @Provides
        @Named("red")
        public Cloth getRedCloth() {
            Cloth cloth = new Cloth();
            cloth.setColor("紅色");
            return cloth;
        }
    
        @Provides
        @Named("blue")
        public Cloth getBlueCloth() {
            Cloth cloth = new Cloth();
            cloth.setColor("藍(lán)色");
            return cloth;
        }
    
        @Provides
        public Clothes getClothes(@Named("blue") Cloth cloth){
            return new Clothes(cloth);
        }
    }
    
    public class MainActivity extends AppCompatActivity {
     ...
     @Inject
     @Named("red")
     Cloth redCloth;
     @Inject
     @Named("blue")
     Cloth blueCloth;
    
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         ...
         tv.setText("我現(xiàn)在有" + redCloth + "和" + blueCloth );
     }
    }
    
  3. @Scope 局部單例橡伞,意思就是在被注入類里只有一個(gè)該類的實(shí)例,局部范圍是啥晋被,那就是它生命周期范圍內(nèi)兑徘。直接上代碼

    //PerActivity.java
    @Scope
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PerActivity {}
    
    //ActivityModule.java
    @Module
    public class ActivityModule {
    
     @Provides
     CoffeeShop provideCoffeeShop(){
         return CoffeeShop.getInstance();//一個(gè)普通的單例
     }
    
     /**
     * 直接在這里說結(jié)果,@PerActivity是用@Scope注解的墨微,除了在這里注解還需要在用到該Module類的Component的類名上方也要注解道媚,然后該實(shí)例在注入到某個(gè)類里的時(shí)候用同一個(gè)Component就會(huì)不管有幾個(gè)字段都會(huì)只有一個(gè)實(shí)例。注意:如果用不同的Component實(shí)例的話仍然會(huì)新的CookerFactory實(shí)例翘县,單例CookerFactory只存在一個(gè)Component實(shí)例里最域。所以叫局部單例。
     */
     @Provides
     @PerActivity
     CookerFactory provideCookerFactory(){
         return new CookerFactory();
     }
    
     @Provides
     CookerFactoryMulty provideCookerFactoryMulty(){
         return new CookerFactoryMulty();//非單例
     }
    }
    
    //CoffeeShop.java
    public class CoffeeShop {
     private static CoffeeShop INSTANCE;
    
     private CoffeeShop(){
         Log.d("TAG","CoffeeShop New Instance");
     }
    
     public static CoffeeShop getInstance(){
         if(INSTANCE == null){
             INSTANCE = new CoffeeShop();
         }
         return INSTANCE;
     }
    }
    
    //CookerFactory.java
    public class CookerFactory {
    
     public CookerFactory(){
         Log.d("TAG","CookerFactory New Instance");
     }
    }
    
    //CookerFactoryMulty.java
    public class CookerFactoryMulty {
    
     public CookerFactoryMulty(){
         Log.d("TAG","CookerFactoryMulty New Instance");
     }
    }
    
    //除了在Module的Provides方法里寫上@Scope還需要在Component類名上方寫上锈麸,這里自定義的@Scope名字叫PerActivity
    @PerActivity
    @Component(modules = {ActivityModule.class})
    public interface ActivityComponent {
     void inject(MainActivity simpleActivity);
    }
    
    public class MainActivity extends Activity {
    
     ActivityComponent activityComponent;
    
     @Inject
     CoffeeShop coffeeShop1;
    
     @Inject
     CoffeeShop coffeeShop2;
    
     @Inject
     CookerFactory cookerFactory1;
    
     @Inject
     CookerFactory cookerFactory2;
    
     @Inject
     CookerFactoryMulty cookerFactoryMulty1;
    
     @Inject
     CookerFactoryMulty cookerFactoryMulty2;
    
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         activityComponent = DaggerActivityComponent.builder()
             //下面這句話可以不寫镀脂,因?yàn)镸odule有默認(rèn)構(gòu)造函數(shù)。如果Module的構(gòu)造器里有參數(shù)忘伞,并且該參數(shù)不是注入進(jìn)去的薄翅,就需要用類似下面的方法手動(dòng)設(shè)置實(shí)例到Component中
                 .activityModule(provideModule())
                 .applicationComponent(MyApplication.getComponent()).build();
         activityComponent.inject(this);
         coffeeFactory.run();
     }
     
     private ActivityModule provideModule(){
         return new ActivityModule();
     }
    }
    

    運(yùn)行結(jié)果

    07-11 16:53:27.978    1927-1927/? D/TAG﹕ CoffeeShop New Instance
    07-11 16:53:27.978    1927-1927/? D/TAG﹕ CookerFactory New Instance
    07-11 16:53:27.978    1927-1927/? D/TAG﹕ CookerFactoryMulty New Instance
    07-11 16:53:27.978    1927-1927/? D/TAG﹕ CookerFactoryMulty New Instance
    
  4. @Singleton 該注解繼承@Scope,用的時(shí)候區(qū)別就是不用去自定義@Scope了氓奈,比如上面定義@PerActivity的這步就不需要了翘魄,其他的用法和使用@PerActivity一模一樣,也是在Component類名上面和Module的Provides方法里都寫上注解舀奶。

注意注意注意:再次提醒暑竟,局部單例是在同一個(gè)Component實(shí)例提供依賴的前提下才有效的,不同的Component實(shí)例只能通過Component依賴才能實(shí)現(xiàn)單例育勺。也就是說但荤,你雖然在兩個(gè)Component接口上都添加了PerActivity注解或者Singleton注解,但是這兩個(gè)Component提供依賴時(shí)是沒有聯(lián)系的涧至,他們只能在各自的范圍內(nèi)實(shí)現(xiàn)單例
在@Inject標(biāo)注的構(gòu)造器上使用局部單例直接在類名上聲明作用范圍(類名上添加@Singleton或自定義Scope)

依賴:dependencies

Component依賴Component的情況下腹躁,兩個(gè)Component的@Scope不能相同,否則會(huì)編譯錯(cuò)誤南蓬,為什么這么設(shè)計(jì)我還不是很清楚纺非,有知道的小伙伴請(qǐng)告訴我謝謝哑了。

依賴的示例代碼如下:

//Person.java
public class Person {
}

//PerActivity.java
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {}

//BaseModule.java
@Module
public class BaseModule {

   @Singleton
   @Provides
   public Person providePerson(){
      return new Person();
   }
}

//Module1.java
@Module
public class Module1 {

}

//Module2.java
@Module
public class Module2 {

}

//BaseComponent.java
@Singleton
@Component(modules = BaseModule.class)
public interface BaseComponent {
    public Person providePerson();
}

//Component1.java
@PerActivity
//@Singleton
//因?yàn)橐蕾嚕╠ependencies)的BaseComponent中用到了@Singleton,所以這個(gè)Component就不能再用了铐炫,否則會(huì)編譯錯(cuò)誤垒手,為什么這么設(shè)計(jì)還不是很清楚
@Component(modules = Module1.class,dependencies = BaseComponent.class)
public interface Component1 {
    void inject(TestScopeActivity1 simpleActivity);
}

//Component2.java
@PerActivity
//@Singleton 為什么不能用?原理同上
@Component(modules = Module2.class,dependencies = BaseComponent.class)
public interface Component2 {
    void inject(TestScopeActivity2 simpleActivity);
}

//MyApplication.java
public class MyApplication extends Application {

    private static BaseComponent baseComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        baseComponent = DaggerBaseComponent.builder().build();
    }

    public static BaseComponent getBaseComponent() {
        return baseComponent;
    }
}

//TestScopeActivity1.java
public class TestScopeActivity1 extends Activity {

    @Inject
    Person p = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerComponent1.builder().baseComponent(MyApplication.getBaseComponent()).build().inject(this);
        TextView textView = findViewById(R.id.textView);
        textView.setText(p.toString());
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(TestScopeActivity1.this,TestScopeActivity2.class));
            }
        });
    }
}

//TestScopeActivity2.java
public class TestScopeActivity2 extends Activity {

    @Inject
    Person p = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerComponent2.builder().baseComponent(MyApplication.getBaseComponent()).build().inject(this);
        TextView textView = findViewById(R.id.textView);
        textView.setText(p.toString());
    }
}

daggar2如何選擇依賴呢倒信,按照這樣的順序

當(dāng)Component調(diào)用inject方法的時(shí)候科贬,會(huì)搜索被注入類中用@Inject注解的字段,然后會(huì)在該Component中查找在@Component(modules=鳖悠。榜掌。。)注解中注冊(cè)的Module乘综,如果搜索到Module有@Provides注解的方法提供該@Inject注解的字段所需的實(shí)例憎账,就調(diào)用相應(yīng)的方法完成注入,否則就查找所有用@Inject注解構(gòu)造函數(shù)的類卡辰,如果找到就調(diào)用相應(yīng)的構(gòu)造函數(shù)完成注入胞皱,如果在獲得實(shí)例的時(shí)候還需要獲取參數(shù)的實(shí)例,再按照剛才的流程依次注入?yún)?shù)實(shí)例

畫個(gè)簡(jiǎn)單的流程九妈,如下所示

Component.inject->在Component搜索Module->找到就調(diào)用@Provides注解的方法提供實(shí)例

? ->沒找到就搜索@Inject注解的構(gòu)造函數(shù)

? ->都找不到就報(bào)錯(cuò)反砌。。萌朱。

都沒找到肯定就報(bào)錯(cuò)了宴树。。晶疼。但是會(huì)優(yōu)先尋找Component注冊(cè)的Module酒贬,而@Inject注冊(cè)的構(gòu)造器可以調(diào)用任何Component的inject方法完成注入,因?yàn)?strong>@Inject注冊(cè)的構(gòu)造器不需要在Component里注冊(cè)翠霍,這里和Module有區(qū)別锭吨,Module是需要在某個(gè)Component中注冊(cè)的,而@Inject不需要

注意:

如果一個(gè)字段需要被@Inject注入寒匙,那么這個(gè)字段的類型必須有@Inject構(gòu)造函數(shù)或者有Module來提供它(還需要在Component添加inject方法或者添加module=[xxx:class])耐齐,如果@Inject一個(gè)父類,而子類的構(gòu)造函數(shù)有@Inject標(biāo)記是沒用的蒋情,類型必須嚴(yán)格對(duì)應(yīng)


舉一個(gè)MVP中使用Dagger2的示例,我就不貼代碼了耸携,直接看下面這個(gè)鏈接好了:

http://www.reibang.com/p/5a936942db2a

參考:

https://dreamerhome.github.io/2016/07/11/dagger%20for%20code/

https://blog.csdn.net/it_zouxiang/article/details/53471192

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末棵癣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子夺衍,更是在濱河造成了極大的恐慌狈谊,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異河劝,居然都是意外死亡壁榕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門赎瞎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來牌里,“玉大人,你說我怎么就攤上這事务甥∧盗桑” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵敞临,是天一觀的道長(zhǎng)态辛。 經(jīng)常有香客問我,道長(zhǎng)挺尿,這世上最難降的妖魔是什么奏黑? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮编矾,結(jié)果婚禮上熟史,老公的妹妹穿的比我還像新娘。我一直安慰自己洽沟,他們只是感情好以故,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著裆操,像睡著了一般怒详。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上踪区,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天昆烁,我揣著相機(jī)與錄音,去河邊找鬼缎岗。 笑死静尼,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的传泊。 我是一名探鬼主播鼠渺,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼眷细!你這毒婦竟也來了拦盹?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤溪椎,失蹤者是張志新(化名)和其女友劉穎普舆,沒想到半個(gè)月后恬口,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡沼侣,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年祖能,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛾洛。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡养铸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出雅潭,到底是詐尸還是另有隱情揭厚,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布扶供,位于F島的核電站筛圆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏椿浓。R本人自食惡果不足惜太援,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望扳碍。 院中可真熱鬧提岔,春花似錦、人聲如沸笋敞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)夯巷。三九已至赛惩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間趁餐,已是汗流浹背喷兼。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留后雷,地道東北人季惯。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像臀突,于是被迫代替她去往敵國(guó)和親勉抓。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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