簡單粗暴的Dagger2使用介紹

安卓基礎(chǔ)開發(fā)庫胎食,讓開發(fā)簡單點。
Demo地址https://github.com/LJYcoder/MvpDagger

學(xué)習/參考地址:
http://www.reibang.com/p/cd2c1c9f68d4
https://blog.csdn.net/lisdye2/article/details/51942511
http://www.reibang.com/p/24af4c102f62

前言

Dagger2已經(jīng)出來挺久了允懂,網(wǎng)上相關(guān)的教程也很多厕怜,普遍都說它比較難上手。
相比起其他框架確實如此蕾总,但只要學(xué)習后加以實踐粥航,還是比較好明白的,說不定你還會從此對它愛不釋手递雀。
我會盡量把它講得容易理解些,如有不當之處蚀浆,還請大家指出糾正缀程。

什么是Dagger2

Dagger2是一個依賴注入(Dependency Injection)框架搜吧。

什么又是依賴注入呢?

借別人的話來說杨凑,就是“目標類中所依賴的其他類的初始化過程滤奈,不是通過在目標類中編碼的方式完成,而是通過其他手段把已經(jīng)初始化好的實例自動注入到目標類中”撩满。

再換種方式來說蜒程,就是把類實例的初始化過程都挪至一個地方統(tǒng)一管理,具體需要哪個實例時鹦牛,就從這個地方取出(注入到目標類中)搞糕。

使用Dagger2有什么好處

知其然勇吊,然后要知其所以然曼追。

1. 解耦

假設(shè)有一個A類,項目中很多地方都使用到它(在很多地方通過new A()對A實例進行了初始化)汉规。然后由于需求變動礼殊,A的構(gòu)造函數(shù)增加了一個參數(shù)。
好了针史,牽一發(fā)而動全身晶伦,你需要把各個new A()的地方都進行修改。
但如果是使用Dagger2進行管理啄枕,你只需在類實例的供應(yīng)端進行修改即可婚陪。

2. 讓功能實現(xiàn)更專注于功能實現(xiàn)

假設(shè)現(xiàn)在你需要調(diào)用A類的x()方法來實現(xiàn)某功能,但是A類的構(gòu)造過程相當?shù)膹?fù)雜(這樣的例子可以參考GreenDao中獲取XXXDao频祝、Retrofit中獲取Observable請求)

public void xxx(){
    E e = new E();
    D d = new D(e);
    C c = new C();
    B b = new B(c,d);
    A a = new A(b)泌参;
    a.x();
}

結(jié)果6行代碼中,構(gòu)造實例a占了5行常空,調(diào)用x()方法實現(xiàn)功能卻只占了1行沽一。
但如果使用Dagger2進行管理,將a實例的構(gòu)造過程移至實例供應(yīng)端漓糙,則功能實現(xiàn)模塊的代碼會變成這樣

@Injcet
A a;
public void xxx(){
    a.x()铣缠;
}

這就是所說的讓功能實現(xiàn)更專注于功能實現(xiàn),而不必去管a實例的構(gòu)造過程昆禽。

3. 更好地管理類實例

通常我們開發(fā)中會有兩種類實例:
一種是全局實例(單例)蝗蛙,它們的生命周期與app保持一致。
一種是頁面實例醉鳖,它們的生命周期與頁面保持一致捡硅。
通過Dagger2,我們可以使用一個組件專門管理全局類實例(也免去了單例的寫法辐棒,不用考慮餓漢懶漢什么的)病曾;然后各個頁面也有各自組件去管理它們的頁面實例牍蜂。
這樣不管是對于實例的管理,還是項目的結(jié)構(gòu)泰涂,都會變得更加的清晰明了鲫竞。

4. 逼格高

(這點可以略過...)
當你不認識Dagger2卻看著使用Dagger2的項目代碼,很可能會感覺到一種茫然與高大上:
各種@Inject逼蒙,@Provides从绘,@Singleton,Lazy<>是牢,Provider<>等是什么鬼僵井?
為什么沒有實例化的代碼?
為什么明明是null卻不會報空指針驳棱?
等你學(xué)會使用Dagger2之后批什,你也可以來一波"高逼格"的代碼贱鄙。

當然贺拣,這里也不得不提一下,使用Dagger2會增加代碼量强衡。所以如果是小項目/獨立開發(fā)形葬,你也可以考慮不用合呐,因為你可能有種失大于得的感覺。如果是大項目/團隊開發(fā)笙以,使用后就得大于失了淌实。


角色介紹

在講用法前,先對幾個重要角色進行了解猖腕。

實例需求端

一個類中拆祈,它包含了實例成員,在使用這些實例前谈息,需要對它們進行初始化缘屹,但前面已經(jīng)說了初始化的過程挪至其他地方。所以這個類的需求是侠仇,已經(jīng)完成初始化的實例對象轻姿。
暫且把這樣的類稱為“實例需求端”。

實例供應(yīng)端

進行實例初始化的地方逻炊,并對外供應(yīng)所需的實例互亮。

Dagger2中,供應(yīng)端有兩種方式可以供應(yīng)實例:(后面會介紹)
第一種:使用Module
第二種:使用@Inject標注構(gòu)造函數(shù)

橋梁

實例供應(yīng)端并不知道它要供應(yīng)的實例交給誰余素。
這個時候就需要通過橋梁豹休,將實例需求端與實例供應(yīng)端聯(lián)系在一起。

Dagger2中桨吊,Component就負責扮演橋梁的角色威根。

使用介紹

1. 初步使用

1.1 添加依賴

compile 'com.google.dagger:dagger:2.14.1'
annotationProcessor 'com.google.dagger:dagger-compiler:2.14.1'

1.2 處理實例需求端

在實例需求端中凤巨,使用@Inject標注需要注入的實例變量。

public class UploadActivity extends AppCompatActivity{
    @Inject
    UploadPresenter mPresenter;
}

1.3 處理實例供應(yīng)端

前面說了洛搀,供應(yīng)端有兩種方式可以供應(yīng)實例敢茁。

方式一 使用Module

  • 使用@Module標注類,表示它為供應(yīng)端
  • 在類中使用@Provides標注方法留美,表示它為提供實例的方法彰檬。
    在該方法中對實例進行初始化并返回該實例。
@Module
public class UploadActivityModule {
    @Provides
    UploadPresenter uploadPresenter() {
        return new UploadPresenter();
    }
}

方式二 使用@Inject標注構(gòu)造函數(shù)

public class UploadPresenter{
    @Inject
    public UploadPresenter() {
    }
}

注意

方式一的優(yōu)先級高于方式二谎砾,意思就是:

  • 在供應(yīng)某實例時逢倍,會先通過方式一查找是否存在返回該實例的的方法
  • 如果存在,則獲取實例并對外供應(yīng)
  • 如果不存在景图,再通過方式二查找是否存在@Inject標注的構(gòu)造函數(shù)
  • 如果存在较雕,則將通過該構(gòu)造函數(shù)構(gòu)造實例并對外供應(yīng)
  • 如果不存在,那將報錯症歇,因為無法供應(yīng)所需的實例

1.4 搭建橋梁

  • 使用@Component標注接口郎笆,表示它為橋梁谭梗。
    (如果使用1.3.1的方式供應(yīng)實例忘晤,則需在@Component(modules=xxx.class)中指明module。)
    一個Component可以沒有module激捏,也可以同時有多個module设塔。
  • 添加 void inject(實例需求端) 方法,表明實例供應(yīng)端中的實例將交給該實例需求端远舅。
    通過這個方法闰蛔,查找實例需求端中需要注入的實例有哪些(使用@Inject標注的那些實例),然后在實例供應(yīng)端中獲取所需的實例图柏,最后注入到實例需求端中
  • 用來注入的方法序六,它的方法名不一定要是inject,可以隨便取蚤吹,一般都取inject例诀。但該方法的返回類型必須為void
@Component(modules = UploadActivityModule.class)
public interface UploadActivityComponent {
    void inject(UploadActivity uploadActivity);
}

1.5 編譯,注入

  • 完成以上幾步后裁着,ReBuild一下項目以生成DaggerUploadActivityComponent類繁涂。
  • 在實例需求端中調(diào)用inject完成實例的注入
public class UploadActivity extends AppCompatActivity{
    @Inject
    UploadPresenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //注入實例
        DaggerUploadActivityComponent.builder()
            .build()
            .inject(this);

        //注入后即可調(diào)用mPresenter中的方法了
        mPresenter.xxx();
    }
}

到此,Dagger2的初步使用就結(jié)束了二驰,下面開始講解些進階用法扔罪。


2. 接收外部參數(shù)

有些時候,實例的初始化需要接收外部參數(shù)才能完成桶雀,比如MVP中的Presenter往往需要傳入IView接口以便完成數(shù)據(jù)回調(diào)矿酵。

現(xiàn)在UploadPresenter的構(gòu)造函數(shù)發(fā)生了變動唬复,需傳入IUploadView。

public class UploadPresenter{
    IUploadView mIView;
    public UploadPresenter(IUploadView iview) {
          mIView = iview;
    }
}

那在供應(yīng)端中全肮,如何接收外部參數(shù)IUploadView呢盅抚?
下面介紹兩種方式:

2.1 方式一 通過Module的構(gòu)造函數(shù)傳入

對實例供應(yīng)端的module進行改造

@Module
public class UploadActivityModule {
    IUploadView mIView;
    public UploadActivityModule(IUploadView iview) {
        mIView = iview;
    }

    @Provides
    IUploadView iUploadView(){
         return mIView;
    }

    @Provides
    UploadPresenter uploadPresenter(IUploadView iview) {
        return new UploadPresenter(iview);
    }
}
  • 添加了構(gòu)造函數(shù)以便獲取外部參數(shù)IUploadView
  • uploadPresenter()方法添加了IUploadView參數(shù)
    • 到時構(gòu)建UploadPresenter實例時,會在這個Module或者同個Component下的其他Module中查找是否存在返回IUploadView的的方法
    • 如果存在倔矾,則通過該方法獲取IUploadView以構(gòu)造UploadPresenter
    • 如果不存在妄均,則通過1.3.2方式查找是否存在@Inject標注的構(gòu)造函數(shù)(這個例子中當然不會存在,因為IUploadView是接口)
  • 不直接使用mIView來構(gòu)造UploadPresenter是為了降低耦合度哪自。uploadPresenter()方法只管獲取構(gòu)造Presenter所需的參數(shù)丰包,而該參數(shù)從哪來、以后會有哪些變動壤巷,交給該參數(shù)的供應(yīng)方法(iUploadView())處理即可邑彪。

利用Module構(gòu)造函數(shù)傳入外部參數(shù)

public class UploadActivity implements IUploadView{
    @Inject
    UploadPresenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //注入實例
        DaggerUploadActivityComponent.builder()
            .uploadActivityModule(new UploadActivityModule(this))//通過構(gòu)造函數(shù)傳入外部參數(shù)IUploadView
            .build()
            .inject(this);

        //注入后即可調(diào)用mPresenter中的方法了
        mPresenter.xxx();
    }

    //實現(xiàn)IUploadView接口的方法
    @Override
    public void onUploadSuccess() {
        //上傳成功
    }
    @Override
    public void onUploadFail() {
        //上傳失敗
    }
}

2.2 方式二 通過Component傳入

對橋梁Component進行改造

@Component(modules = UploadActivityModule.class)
public interface UploadActivityComponent {
    void inject(UploadActivity uploadActivity);

    IUploadView iUploadView();

    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder iUploadView(IUploadView iUploadView);

        UploadActivityComponent build();
    }
}
  • 加入iUploadView()方法返回IUploadView
  • 加入了Builder來接收IUploadView

構(gòu)建Component時傳入外部參數(shù)

public class UploadActivity extends AppCompatActivity implements IUploadView{
    @Inject
    UploadPresenter mPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //注入實例
        DaggerUploadActivityComponent.builder()
            .iUploadView(this)
            .build()
            .inject(this);

        //注入后即可調(diào)用mPresenter中的方法了
        mPresenter.xxx();
    }

    //實現(xiàn)IUploadView接口的方法
    @Override
    public void onUploadSuccess() {
        //上傳成功
    }
    @Override
    public void onUploadFail() {
        //上傳失敗
    }
}


3. 限定符注解 @Qualifier

@Qualifier主要是用于解決,因?qū)嵗?yīng)端存在多個返回類型相同的供應(yīng)方法而引起歧義的問題胧华。
下面舉個例子寄症,現(xiàn)在頁面需有兩個Dialog,一個用于登錄矩动,一個用于注冊有巧。

3.1 使用@Named注解區(qū)分

Dagger2默認提供了一個@Named注解,從代碼可以看出屬于@Qualifier的一種實現(xiàn)悲没。

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
    String value() default "";
}

在供應(yīng)端對兩個Dialog進行構(gòu)造篮迎。

@Module
public class TestActivityModule {
    private Context mContext;

    public TestActivityModule(Context context){
          mContext = context;
    }

    @Provides
    Context context(){
          return mContext;
    }
    
    @Named("login")
    @Provides
    Dialog loginDialog(Context context){
         Dialog dialog = new Dialog(context);
         dialog.setTitle("登錄提示");
         ....
         return dialog;
    }

    @Named("register")
    @Provides
    Dialog registerDialog(Context context){
         Dialog dialog = new Dialog(context);
         dialog.setTitle("注冊提示")示姿;
         ....
         return dialog;
    }
}
  • 可以看到甜橱,在實例供應(yīng)端中,需在提供Dialog實例的方法上面加@Named注解以區(qū)分栈戳。如果不加則會報錯岂傲,因為Dagger2不知道要使用哪個方法來獲取Dialog實例。
@Component(modules = TestActivityModule.class)
public interface TestActivityComponent {
    void inject(TestActivity testActivity);
}
public class TestActivity extends AppCompatActivity{
    @Named("login")
    @Inject
    Dialog mDialogLogin;
    
    @Named("register")
    @Inject
    Dialog mDialogRegister;      

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //注入實例
        DaggerTestActivityComponent.builder()
            .testActivityModule(new TestActivityModule(this))
            .build()
            .inject(this);
    }    
}
  • 在實例需求端中子檀,同樣要使用@Named注解標注要注入的實例镊掖。讓Dagger2知道,
    @Named("login")標注的mDialogLogin命锄,需要通過@Named("login")標注的供應(yīng)方法來獲取堰乔。
    @Named("register")標注的mDialogRegister,需要通過@Named("register")標注的供應(yīng)方法來獲取脐恩。

3.2 使用自定義@Qualifier區(qū)分

使用@Named注解的話镐侯,需要加入字符串來區(qū)分,這樣比較麻煩也容易出錯。所以我們可以使用自定義的限定符注解苟翻。

@Qualifier
public @interface DialogLogin {
}
@Qualifier
public @interface DialogRegister {
}

然后把前面涉及的@Named("login")換成@DialogLogin韵卤,@Named("register")換成@DialogRegister即可~


4. 作用域注解 @Scope

@Scope的作用是使同一個Component中供應(yīng)的實例保持唯一。

4.1 使用作用域注解實現(xiàn)局部單例

舉例說明:

public class UploadActivity extends AppCompatActivity{
    @Inject
    UploadPresenter mPresenter1;
    @Inject
    UploadPresenter mPresenter2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //注入實例
        DaggerUploadActivityComponent.builder()
            .build()
            .inject(this);
    }
}
  • 如果不使用作用域注解崇猫,則代碼中的mPresenter1沈条,mPresenter2將會是兩個不一樣的實例,可通過打印內(nèi)存地址查看诅炉。
  • 而如下使用作用域注解后蜡歹,則兩者將會是同一個實例,可通過打印內(nèi)存地址查看涕烧。

步驟1 自定義@Scope注解

@Scope
@Documented
@Retention(RUNTIME)
public @interface ActivityScope {}

步驟2 橋梁Component添加作用域注解

@ActivityScope 
@Component(modules = UploadActivityModule.class)
public interface UploadActivityComponent {
    void inject(UploadActivity uploadActivity);
}

步驟3 供應(yīng)端中提供實例的方法添加作用域注解

@Module
public class UploadActivityModule {
    @ActivityScope
    @Provides
    UploadPresenter uploadPresenter() {
        return new UploadPresenter();
    }
}

如果是使用1.3.2方式提供實例月而,則在類上方添加作用域注解

@ActivityScope
public class UploadPresenter{
    @Inject
    public UploadPresenter() {
    }
}

經(jīng)過@Scope處理后,UploadActivity中的UploadPresenter實例將保持唯一议纯。

4.2 使用作用域注解實現(xiàn)全局單例

全局單例父款,相信大家就很熟悉了,就是平時用餓漢懶漢等等寫的那種單例模式瞻凤。
前面已經(jīng)說過@Scope作用是使同一個Component中供應(yīng)的實例保持唯一憨攒。
也就是說,如果我在另一個Activity中再創(chuàng)建了一個新的Component阀参,那么它所提供的UploadPresenter實例也將是新的肝集。這和我們理解的全局單例并不一樣。
所以结笨,要想實現(xiàn)全局單例包晰,那就要確保獲取實例的Component一直都是同一個
如何實現(xiàn)呢炕吸?
答案是創(chuàng)建一個Component用于提供全局單例的實例(創(chuàng)建過程和4.1基本一樣),然后在Application中對該Component進行初始化勉痴,以后要獲取單例時赫模,都統(tǒng)一通過它來獲取

全局性的實例供應(yīng)端

@Module
public class AppModule {
    private Application mApplication;

    public AppModule (Application application){
          mApplication = application;
    }

    @Singleton
    @Provides
    Application application(){
          return mApplication;
    }

    @Singleton
    @Provides
    ActivityStackManager activityStackManager() {
        return new ActivityStackManager();
    }
}

全局性的橋梁

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    ActivityStackManager activityStackManager();
    Application application();
}

Application中初始化

public class MyApplication extends Application {

    public static AppComponent mAppComponent;

    @Override
    public void onCreate() {
        super.onCreate();
       
        mAppComponent= DaggerAppComponent.builder()
              .appModule(new AppModule(this))
              .build();
    }
}

每次都通過Application中的AppComponent獲取某實例蒸矛,即可保證全局單例

public class UploadActivity extends AppCompatActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
   
        MyApplication.mAppComponent.activityStackManager().pushOneActivity(this);     
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        MyApplication.mAppComponent.activityStackManager().popOneActivity(this);   
    }
}
  • 使用了Dagger2默認提供的作用域注解@Singleton瀑罗,通過源碼可以發(fā)現(xiàn)它的實現(xiàn)其實和前面的@ActivityScope是一樣的。
  • 所以真正實現(xiàn)全局單例的不是并@Singleton雏掠,而是使用每次獲取實例都通過同一個Component斩祭。
  • 但由于它的字面意思為單例,所以我們通常把它應(yīng)用在全局性的橋梁和實例供應(yīng)端中乡话。
  • 全局性的Component中沒有加入inject方法來自動注入(當然你也可以這么做摧玫,但全局性的比較少這么做),而是加入了activityStackManager()方法绑青,供外部調(diào)用來獲取實例诬像。


5. Lazy<T> 和 Provider<T>

假如你并不希望在調(diào)用inject()方法后屋群,就對@Inject標注的實例進行初始化注入,而是希望在用到該實例的時候再進行初始化坏挠,那么我們就可以使用Lazy<T>和Provider<T>來實現(xiàn)芍躏。

舉例說明(省略實例供應(yīng)端和橋梁的代碼)

public class UploadActivity extends AppCompatActivity{
    @Inject
    Lazy<UploadPresenter> mPresenter1;
    @Inject
    Provider<UploadPresenter> mPresenter2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //注入實例
        DaggerUploadActivityComponent.builder()
            .build()
            .inject(this);
    }

    public void xxx(){
         //調(diào)用Lazy的get()方法后才開始初始化Presenter并得到該實例
         //并且后面每次調(diào)用get()方法得到的實例都將是同一個。
         mPresenter1.get().xxx();

         //調(diào)用Provider的get()方法后才開始初始化Presenter并得到該實例
         //并且后面每次調(diào)用get()方法降狠,都會重新調(diào)用供應(yīng)端的供應(yīng)方法來獲取新實例对竣。
         mPresenter2.get().xxx();
    }
}

注意: 如果使用了前面介紹的作用域注解@Scope控制了實例的唯一性,那么即使多次調(diào)用Provider的get()方法榜配,得到的依然是同一個實例柏肪。


6. 依賴 和 包含

假設(shè)A供應(yīng)端某個實例的初始化過程需要用到X實例,而X實例在其他橋梁連接的B供應(yīng)端中有提供芥牌,那么我們可以我們可以通過橋梁間的依賴或包含烦味,從B供應(yīng)端獲取需要的實例,這樣就不用再在A供應(yīng)端中寫X實例的提供方法了壁拉。
比如下面代碼中谬俄,DbHelper的初始化需要用到全局的Context(即Application),那么我們可以通過橋梁間的依賴或包含弃理,從前面提及的全局AppComponent中獲取溃论。

@Module
public class TestActivityModule {
    //需要使用到Application參數(shù)
    @Provides
    DbHelper dbHelper(Application application){
          return new DbHelper(application);
    }
}

6.1 通過依賴實現(xiàn)(TestActivityComponent依賴AppComponent)

通過dependencies = xxx.classs指定要依賴的Component :

@Component(modules = TestActivityModule.class, dependencies = AppComponent.class)
public interface TestActivityComponent {
   void inject(TestActivity testActivity);
}

被依賴的Component中需定義相關(guān)實例的獲取方法 :

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {

    Application application();
    ...
}

初始化TestActivityComponent時需傳入依賴的Component

public class TestActivity extends AppCompatActivity{

    @Inject
    DbHelper mDbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        DaggerTestActivityComponent.builder()
            .appComponent(MyApplication.mAppComponent) //傳入依賴的Component
            .build()
            .inject(this);
    }    
}

6.2 通過包含實現(xiàn)(AppComponent包含TestActivityComponent)

TestActivityComponent使用@Subcomponent注解而不是@Component

@Subcomponent(modules = TestActivityModule.class)
public interface TestActivityComponent {
    void inject(TestActivity testActivity);
}

AppComponent中定義相關(guān)方法,用來包含和獲取SubComponent

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {

    TestActivityComponent addSub(TestActivityModule testActivityModule);
    ...
}

通過AppComponent來獲取SubComponent痘昌,然后注入

public class TestActivity extends AppCompatActivity{

    @Inject
    DbHelper mDbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        TestActivityComponent testActivityComponent = MyApplication.mAppComponent.addSub(new TestActivityModule());
        testActivityComponent .inject(this);
            
    }    
}

6.3 依賴和包含使用小結(jié)

  • 通過橋梁Component之間的依賴或包含钥勋,可以獲取到其他橋梁所連接的供應(yīng)端提供的實例。
  • 使用依賴實現(xiàn)的話(假設(shè)A依賴B)辆苔,A需通過dependencies指定依賴B算灸,B中需定義A所需的相關(guān)實例的獲取方法,A構(gòu)造時需傳入B驻啤。
  • 使用包含實現(xiàn)的話(假設(shè)B包含A)菲驴,A需使用@Subcomponent標注,B中需定義方法來包含/獲取A骑冗,A是通過調(diào)用B的方法來獲取的赊瞬。
  • 具有依賴關(guān)系的兩個Component,它們的作用域注解@Scope必須不同贼涩,否則會引起歧義巧涧。


7. 一些Tips

Tips1:
在1.3.1和1.3.2介紹了兩種實例供應(yīng)方式:
方式一:使用Module。
方式二:使用@Inject標注構(gòu)造函數(shù)遥倦。
那什么時候應(yīng)該使用哪種方式呢谤绳?
假設(shè)現(xiàn)在供應(yīng)端需要提供A類的實例

  • 當無法在A類的構(gòu)造函數(shù)上加入@Inject時(比如一些第三方庫里的類),則使用方式一提供A實例。
  • 當你希望在A類實例初始化時闷供,A類中被@Inject標注的變量也被自動注入烟央,則使用方式二提供A實例。

Tips2:
Module類可以聲明為abstract抽象歪脏,但相關(guān)的供應(yīng)方法需聲明為static靜態(tài)方法疑俭。

Tips3:
@inject標注的實例變量不能聲明為private,也不能為static婿失,否則會編譯報錯钞艇。

Tips4:
如果module中的供應(yīng)方法聲明了@Scope,那么它所屬的component必須也聲明相同的@Scope豪硅。
但如果component聲明了@Scope哩照,它的module的供應(yīng)方法并不一定全都要聲明@Scope。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末懒浮,一起剝皮案震驚了整個濱河市飘弧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌砚著,老刑警劉巖次伶,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異稽穆,居然都是意外死亡冠王,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門舌镶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柱彻,“玉大人,你說我怎么就攤上這事餐胀∮纯” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵骂澄,是天一觀的道長吓蘑。 經(jīng)常有香客問我,道長坟冲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任溃蔫,我火速辦了婚禮健提,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘伟叛。我一直安慰自己私痹,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著紊遵,像睡著了一般账千。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上暗膜,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天匀奏,我揣著相機與錄音,去河邊找鬼学搜。 笑死娃善,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的瑞佩。 我是一名探鬼主播聚磺,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼炬丸!你這毒婦竟也來了瘫寝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤稠炬,失蹤者是張志新(化名)和其女友劉穎焕阿,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酸纲,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡捣鲸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了闽坡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片栽惶。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖疾嗅,靈堂內(nèi)的尸體忽然破棺而出外厂,到底是詐尸還是另有隱情,我是刑警寧澤代承,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布汁蝶,位于F島的核電站,受9級特大地震影響论悴,放射性物質(zhì)發(fā)生泄漏掖棉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一膀估、第九天 我趴在偏房一處隱蔽的房頂上張望幔亥。 院中可真熱鬧,春花似錦察纯、人聲如沸帕棉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽香伴。三九已至慰枕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間即纲,已是汗流浹背具帮。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留崇裁,地道東北人匕坯。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像拔稳,于是被迫代替她去往敵國和親葛峻。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

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