日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

依赖注入利器 - Dagger ‡

發(fā)布時間:2024/1/17 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 依赖注入利器 - Dagger ‡ 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉(zhuǎn)載請標明出處:http://blog.csdn.net/shensky711/article/details/53715960
本文出自: 【HansChen的博客】

  • 概述
  • 聲明需要注入的對象
  • 如何實例化出依賴
  • Module的使用
  • Component的使用
  • Dagger的進階使用
    • Components之間的關(guān)系
      • dependencies
      • Subcomponents
    • Scopes
    • Singlton
    • 自定義Scope
    • scope的作用
    • Lazy注入
    • Provider注入
    • Qualifiers注入
    • 編譯時驗證
  • 小結(jié)

概述

在開發(fā)過程中,為了實現(xiàn)解耦,我們經(jīng)常使用依賴注入,常見的依賴注入方式有:

  • 構(gòu)造方法注入:在構(gòu)造方法中把依賴作為參數(shù)傳遞進去
  • setter方法注入:添加setter方法,把依賴傳遞進去
  • 接口注入:把注入方法抽到一個接口中,然后實現(xiàn)該接口,把依賴傳遞進去

下面用一個小栗子來說明三種方式的用法:

public class PersonService implements DependencyInjecter {private PersonDao personDao;// 構(gòu)造方法注入public PersonService(PersonDao personDao) {this.personDao = personDao;}// setter方法注入public void setPersonDao(PersonDao personDao) {this.personDao = personDao;}// 接口注入:實現(xiàn)DependencyInjecter接口@Overridepublic void injectPersonDao(PersonDao personDao) {this.personDao = personDao;}... ... }

我們來看下使用一般的依賴注入方法時,代碼會是怎么樣的:

public class MainActivity extends AppCompatActivity {private PersonService mService;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 創(chuàng)建PersonService的依賴:personDaoPersonDao personDao = new PersonDaoImpl();// 通過構(gòu)造方法注入依賴mService = new PersonService(personDao);} }

看起來還好是吧?但現(xiàn)實情況下,依賴情況往往是比較復(fù)雜的,比如很可能我們的依賴關(guān)系如下圖:

PersonDaoImpl依賴類A,類A依賴B,B依賴C和D…在這種情況下,我們就要寫出下面這樣的代碼了:

public class MainActivity extends AppCompatActivity {private PersonService mService;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 創(chuàng)建依賴DD d = new D();// 創(chuàng)建依賴CC c = new C();// 創(chuàng)建依賴BB b = new B(c, d);// 創(chuàng)建依賴AA a = new A(b);// 創(chuàng)建PersonService的依賴:personDaoPersonDao personDao = new PersonDaoImpl(a);// 通過構(gòu)造方法注入依賴mService = new PersonService(personDao);} }

MainActivity只是想使用PersonService而已,卻不得不關(guān)注PersonService的依賴是什么、PersonDaoImpl依賴的依賴是什么,需要把整個依賴關(guān)系搞清楚才能使用PersonService。而且還有一個不好的地方,一旦依賴關(guān)系變更了,比如A不再依賴B了,那么就得修改所有創(chuàng)建A的地方。那么,有沒有更好的方式呢?Dagger就是為此而生的,讓我們看看使用Dagger后,MainActivity會變成什么模樣:

public class MainActivity extends AppCompatActivity {@InjectPersonService mService;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// Dagger注入,讀者現(xiàn)在可先不關(guān)注里面做了什么操作DaggerPersonServiceComponent.create().inject(MainActivity.this);// 注意,mService已經(jīng)是非空了,可以正常使用mService.update(1, "HansChen");......} }

之前創(chuàng)建A、B、C、D、PersonDaoImpl等依賴的代碼全不見了,只需要調(diào)用一個注入語句就全搞定了。調(diào)用了注入語句之后,mService就可以正常使用了,是不是挺方便呢?至于這句注入語句具體干了什么,讀者現(xiàn)在可以先不管,后面會有詳細說明,這里只是做一個使用演示而已。

我們大概猜想一下,在MainActivity使用PersonService需要做哪些?

  • 分析生成依賴關(guān)系圖,如PersonService–>PersonDaoImpl–>A–>B–>C&D
  • 根據(jù)依賴關(guān)系圖獲取相關(guān)依賴,比如依次創(chuàng)建D、C、B、A、PersonDaoImpl、PersonService的實例
  • 把生成的PersonService實例傳遞給MainActivity的mService成員變量
  • 其實Dagger做的也就是上面這些事情了,接下來就讓我們真正開始學(xué)習(xí)Dagger吧

    聲明需要注入的對象

    首先我們應(yīng)該用javax.inject.Inject去注解需要被自動注入的對象,@Inject是Java標準的依賴注入(JSR-330)注解。比如下面栗子中,需要注入的對象就是MainActivity的mService。這里有個要注意的地方,被@Inject注解的變量不能用private修飾

    public class MainActivity extends AppCompatActivity {// 注意,不能被private修飾@InjectPersonService mService;...... }

    如何實例化出依賴?

    在執(zhí)行依賴注入的時候,Dagger會查找@Inject注解的成員變量,并嘗試獲取該類的實例,Dagger最直接的方式就是直接new出相應(yīng)的對象了。實例化對象的時候,會調(diào)用對象的構(gòu)造方法,但假如有多個構(gòu)造方法,具體用哪個構(gòu)造方法來實例化對象?Dagger肯定是不會幫我們“擅自做主”的,用哪個構(gòu)造方法來實例化對象應(yīng)該是由我們做主的,所以我們需要給相應(yīng)的構(gòu)造方法添加@Inject注解。
    當Dagger需要實例化該對象的時候,會調(diào)用@Inject注解的構(gòu)造方法來實例化對象:

    public class PersonService implements DependencyInjecter {private PersonDao personDao;// 用@Inject注解,相當于告訴Dagger需要實例化PersonService的時候,請調(diào)用這個構(gòu)造方法@Injectpublic PersonService(PersonDao personDao) {this.personDao = personDao;}...... }

    聰明的你應(yīng)該發(fā)現(xiàn)了,調(diào)用PersonService的構(gòu)造方法需要傳入PersonDao實例,所以要實例化PersonService,必須先要實例化PersonDao,Dagger會幫我們自動分析出這個依賴關(guān)系,并把它添加到依賴關(guān)系圖里面!Dagger會嘗試先去實例化一個PersonDao,如果PersonDao又依賴于另外一個對象A,那么就先嘗試去實例化A……以此類推,是不是很像遞歸?當所有依賴都被實例化出來之后,我們的PersonService當然也被構(gòu)造出來了。

    問題又來了,如果PersonDao是一個接口呢?Dagger怎么知道這個接口應(yīng)該怎么實現(xiàn)?答案是不知道的,那么Dagger怎么實例化出一個接口出來?這個就是Module存在的意義之一了。關(guān)于Module的講解我們會在后面詳細說明,我們現(xiàn)在只要知道,Module里面會定義一些方法,這些方法會返回我們的依賴,就像:

    @Module public class PersonServiceModule {/*** 提供PersonDao接口實例*/@ProvidesPersonDao providePersonDao(A a) {return new PersonDaoImpl(a);} }

    Dagger根據(jù)需求獲取一個實例的時候,并不總是通過new出來的,它會優(yōu)先查找Module
    中是否有返回相應(yīng)實例的方法,如果有,就調(diào)用Module的方法來獲取實例。

    比如你用@Inject注解了一個成員變量,Dagger會查找Module中是否有用@Provides注解的,返回該類實例的方法,有的話就會調(diào)用provide方法來獲得實例,然后注入,如果沒有的話Dagger就會嘗試new出一個實例。就像我們現(xiàn)在這個栗子,PersonService依賴于PersonDao接口,Dagger不能直接為我們new出一個接口,但我們可以提供一個Module,在Module中定義一個返回PersonDao接口實例的方法,這樣,Dagger就可以解決實例化PersonDao的問題了。

    我們再梳理一下流程,如果我們用@Inject注解了一個成員變量,并調(diào)用注入代碼之后,Dagger會這樣處理:

  • 查找Module中是否有用@Provides注解的,返回該類實例的方法
  • 如果有,就調(diào)用那個provide方法來獲得實例,然后注入
  • 如果沒有,就嘗試調(diào)用相應(yīng)的類中被@Inject注解的構(gòu)造方法new出一個實例,然后注入
  • 如果沒有一個構(gòu)造方法被@Inject注解,Dagger會因不能滿足依賴而出錯
  • 所以假如一個變量被@Inject注解,要么在Module中提供provide方法獲取實例,要么該類提供一個被@Inject注解的構(gòu)造方法,否則Dagger會出錯

    Module的使用

    一般而言,Dagger會獲取所有依賴的實例,比如當需要一個TestBean的時候,會通過new TestBean()創(chuàng)建實例并注入到類中。但是,以下情況會就不好處理了:

  • 需要生成的是一個接口,而Dagger不能直接實例化接口
  • 不能在第三方庫的類中添加注解
  • 可配置的對象必須是配置的
  • 為了解決以上問題,我們需要定義一個被@Module注解的類,在里面定義用@Provides注解的方法。用該方法返回所需的實例。

    @Module public class PersonServiceModule {@ProvidesD provideD() {return new D();}@ProvidesC provideC() {return new C();}@ProvidesB provideB(C c, D d) {return new B(c, d);}@ProvidesA provideA(B b) {return new A(b);}/*** 提供PersonDao實例*/@ProvidesPersonDao providePersonDao(A a) {return new PersonDaoImpl(a);} }

    就像providePersonDao返回了PersonDao接口實例,Dagger雖然不能直接實例化出PersonDao接口,但卻可以調(diào)用Module的providePersonDao方法來獲得一個實例。providePersonDao方法需要傳入A的實例,那么這里也構(gòu)成了一個依賴關(guān)系圖。Dagger會先獲取A的實例,然后把實例傳遞給providePersonDao方法。

    Component的使用

    到目前為止,我們雖然知道了:

    • Dagger怎么獲取實例:
      • 從Module的provide方法中獲取
      • 通過@Inject注解的構(gòu)造方法new出新的實例
    • Dagger會推導(dǎo)provide方法和構(gòu)造方法的參數(shù),形成依賴圖,并“滿足”我們依賴圖的需求,獲取依賴的實例

    看樣子需要注入的依賴可以獲取了,但是不是總覺得還有點“零碎”,整個流程還沒連貫起來?比如,Module既然是一個類,生成依賴圖的時候,怎么知道跟哪個Module掛鉤?即使最后生成了需要的實例,注入的“目的地”是哪里?怎么才能把它注入到“目的地”?殘缺的這部分功能,正是Component提供的,Component起到了一個橋梁的作用,貫通Module和注入目標。我們來看看最開始那個例子,我們是怎么進行依賴注入的:

    public class MainActivity extends AppCompatActivity {@InjectPersonService mService;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);PersonServiceComponent component = DaggerPersonServiceComponent.builder().personServiceModule(new PersonServiceModule()).build();// 注入,所有@Inject注解的成員變量都會同時注入component.inject(MainActivity.this);// 通過component獲取實例,注意,這里只是演示用法,其實mService在component.inject的時候已經(jīng)完成了注入mService = component.getPersonService();} }

    這個DaggerPersonServiceComponent是什么鬼?DaggerPersonServiceComponent其實是Dagger為我們自動生成的類,它實現(xiàn)了一個Component接口(這個接口是需要我們自己寫的),我們來看下它實現(xiàn)的接口長什么樣子:

    /*** 指定PersonServiceModule,當需要獲取某實例的時候,會查找PersonServiceModule中是否有返回相應(yīng)類型的方法,有的話就通過該方法獲得實例** @author HansChen*/ @Component(modules = PersonServiceModule.class) public interface PersonServiceComponent {/*** 查找activity中被@Inject注解的成員變量,并嘗試獲取相應(yīng)的實例,把實例賦給activity的成員變量* 注意函數(shù)格式:返回值為空、帶有一個參數(shù)*/void inject(MainActivity activity);/*** Dagger會嘗試從Module中獲取PersonService實例,如果Module中不能獲取對應(yīng)實例,則通過PersonService的構(gòu)造方法new出一個實例* 注意函數(shù)格式:參數(shù)為空,返回值非空*/PersonService getPersonService(); }

    這個接口被Component注解修飾,它里面可以定義3種類型的方法:

    • 返回值為空,有一個參數(shù):查找參數(shù)中被@Inject注解的成員變量,并嘗試獲取相應(yīng)的實例(通過Module的provide方法或@Inject注解的構(gòu)造方法new出新的實例),把實例賦給參數(shù)的成員變量
    • 返回值非空,參數(shù)為空:獲取相應(yīng)實例并返回
    • 返回值是Component,參數(shù)是Moduld,通過該方法可以創(chuàng)建SubComponent實例

    既然獲取實例的時候,有可能用到Module,那么就必須為這個Component指定使用的Module是什么。具體做法就是在@Component注解中指定modules。
    定義好Component之后,Dagger會自動幫我們生成實現(xiàn)類,這就是Dagger強大的地方!生成的類名格式是:Dagger+Component名。
    Component提供了2種方法,一個是注入式方法,一個是獲取實例方法。具體用什么方法,就看個人需求了。一個Component其實也對應(yīng)了一個依賴圖,因為Component使用哪個Module是確定不變的,依賴關(guān)系無非也就是跟Module和類的定義有關(guān)。一旦這些都確定下來了,在這個Component范圍內(nèi),依賴關(guān)系也就被確定下來了。額外再說一點,在Dagger1中,Component的功能是由ObjectGraph實現(xiàn)的,Component是用來代替它的。

    Component定義好之后,build一下工程,Dagger就會自動為我們生成實現(xiàn)類了,就可以使用自動生成的實現(xiàn)類來進行依賴注入了。到現(xiàn)在為止,我們已經(jīng)通過Dagger完成了依賴注入??赡芸雌饋肀日7椒闊┑枚?#xff0c;但是Dagger框架可以讓依賴的注入和配置獨立于組件之外,它幫助你專注在那些重要的功能類上。通過聲明依賴關(guān)系和指定規(guī)則構(gòu)建整個應(yīng)用程序。

    熟悉完Dagger基本的使用之后,接下來我們來講解一些稍微高級一點的用法:

    Dagger的進階使用

    Components之間的關(guān)系

    在Dagger中,Component之間可以有兩種關(guān)系:Subcomponents和Component dependencies。他們有什么作用呢?比如在我們應(yīng)用中,經(jīng)常會有一些依賴我們在各個界面都使用得到,比如操作數(shù)據(jù)庫、比如網(wǎng)絡(luò)請求。假設(shè)我們有個ServerApi的接口,在頁面A、B、C都使用到了,那么我們要在頁面A、B、C的Component里面都能獲取到ServerApi的實例,但顯然,獲取ServerApi實例的方法都是一樣的,我們不想寫重復(fù)的代碼。于是我們可定義一個ApplicationComponent,在里面返回ServerApi實例,通過Component之間的關(guān)系便可以共享ApplicationComponent提供的依賴圖。

    下面通過Android中的一個小栗子來說明Subcomponents和Component dependencies如何使用

    dependencies

    先說明下各個模塊之間的關(guān)系
    首先,我們定義一個ApplicationComponent,它定義了一個方法,通過它來獲得ServerApi實例。ApplicationComponent還關(guān)聯(lián)了ApplicationModule,這個Module是ServerApi實例的提供者,注意,這個Moduld還可以返回Context實例

    @Component(modules = ApplicationModule.class) public interface ApplicationComponent {ServerApi getServerApi(); } @Module public class ApplicationModule {private final Context mAppContext;ApplicationModule(Context context) {mAppContext = context.getApplicationContext();}@ProvidesContext provideAppContext() {return mAppContext;}@ProvidesServerApi provideServerApi(Context context) {return new ServerApiImpl(context);} } public class DemoApplication extends Application {private ApplicationComponent mAppComponent;@Overridepublic void onCreate() {super.onCreate();mAppComponent = DaggerApplicationComponent.builder().applicationModule(new ApplicationModule(this)).build();}public ApplicationComponent getAppComponent() {return mAppComponent;} }

    MainActivity使用MVP模式,在MainPresenter里面需要傳入一個ServerApi對象

    // 注意,這里有個dependencies聲明 @Component(dependencies = ApplicationComponent.class, modules = MainPresenterModule.class) public interface MainPresenterComponent {MainPresenter getMainPresenter(); } @Module public class MainPresenterModule {private MainView mMainView;public MainPresenterModule(MainView mainView) {this.mMainView = mainView;}@ProvidesMainView provideMainView() {return mMainView;} } public class MainPresenter {private MainView mMainView;private ServerApi mServerApi;@Injectpublic MainPresenter(MainView mainView, ServerApi serverApi) {this.mMainView = mainView;this.mServerApi = serverApi;} }

    先拋開dependencies,我們分析這個這個依賴樹是怎么樣的

    Component中g(shù)etMainPresenter的目的很簡單,就是返回MainPresenter,而MainPresenter又依賴MainView和ServerApi,MainView還好說,在MainPresenterModule中有provide方法,但是ServerApi呢?就像上面說的那樣,如果我們在這個Moduld中也添加相應(yīng)的provide方法,那真是太麻煩了(當然,這樣做完全是可以實現(xiàn)的),所以我們依賴了ApplicationComponent,通過dependencies,在被依賴的Component暴露的對象,在子Component中是可見的。這個是什么意思呢?意思有兩個:

  • 被依賴Component接口暴露的對象,可以添加到依賴者的依賴圖中
  • Component接口沒有暴露的對象,依賴者是不可見的
  • 對于第一點應(yīng)該比較好理解,就像這個栗子,MainPresenterComponent生成MainPresenter需要ServerApi,而ApplicationComponent中有接口暴露了ServerApi,所以MainPresenterComponent可以獲得ServerApi
    對于第二點,假設(shè)MainPresenter還需要傳入一個Context對象,我們注意到,ApplicationModule是可以提供Context的,那MainPresenterComponent能不能通過ApplicationComponent獲取Context實例?答案是不行的,因為ApplicationComponent沒有暴露這個對象。想要獲取Context,除非ApplicationComponent中再添加一個getContext的方法。

    他們之間的關(guān)系可以用下圖描述:

    Subcomponents

    讓我們對上面的栗子改造改造:
    去除MainPresenterComponent的Component注解,改為Subcomponent:

    @Subcomponent(modules = MainPresenterModule.class) public interface MainPresenterComponent {void inject(MainActivity activity);MainPresenter getMainPresenter(); }

    在ApplicationComponent中新增plus方法(名字可隨意取),返回值為MainPresenterComponent,參數(shù)為MainPresenterModule:

    @Component(modules = ApplicationModule.class) public interface ApplicationComponent {MainPresenterComponent plus(MainPresenterModule module); }

    這樣,就構(gòu)建了一個ApplicationComponent的子圖:MainPresenterComponent。子圖和dependencies的區(qū)別就是,子圖可以范圍父圖所有的依賴,也就是說,子圖需要的依賴,不再需要在父Component中暴露任何對象,可以直接通過父圖的Moduld提供!他們的關(guān)系變?yōu)榱?#xff1a;

    Scopes

    Scopes可是非常的有用,Dagger2可以通過自定義注解限定注解作用域。@Singleton是被Dagger預(yù)先定義的作用域注解。

    • 沒有指定作用域的@Provides方法將會在每次注入的時候都創(chuàng)建新的對象
    • 一個沒有scope的component不可以依賴一個有scope的組件component
    • 子組件和父組件的scope不能相同
    • Module中provide方法的scope需要與Component的scope一致

    我們通常的ApplicationComponent都會使用Singleton注解,也就會是說我們?nèi)绻远xcomponent必須有自己的scope。讀者到這里,可能還不能理解Scopes的作用,我們先來看下默認提供的Singlton到底有什么作用,然后再討論Scopes的意義:

    Singlton

    Singletons是java提供的一個scope,我們來看看Singletons能做什么事情。
    為@Provides注釋的方法或可注入的類添加添加注解@Singlton,構(gòu)建的這個對象圖表將使用唯一的對象實例,比如我們有個ServerApi
    方法一:用@Singleton注解類:

    @Singleton public class ServerApi {@Injectpublic ServerApi() {}public boolean login(String username, String password) {return "HansChen".equals(username) && "123456".equals(password);} }

    方法二:用@Singleton注解Module的provide方法:

    @Module public class ApplicationModule {@Singleton@ProvidesServerApi provideServerApi() {return new ServerApi();} }

    然后我們有個Component:

    @Singleton @Component(modules = ApplicationModule.class) public interface ApplicationComponent {ServerApi getServerApi(); }

    然后執(zhí)行依賴注入:

    public class MainActivity extends AppCompatActivity {@InjectServerApi mService;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ApplicationComponent component = DaggerApplicationComponent.create();Log.d("Hans", component.getServerApi().toString());Log.d("Hans", component.getServerApi().toString());Log.d("Hans", component.getServerApi().toString());} }

    使用了以上兩種方法的任意一種,我們都會發(fā)現(xiàn),通過component.getServerApi()獲得的實例都是同一個實例。不過要注意一點的是,如果類用@Singleton注解了,但Module中又存在一個provide方法是提供該類實例的,但provide方法沒有用@Singleton注解,那么Component中獲取該實例就不是單例的,因為會優(yōu)先查找Module的方法。
    這個單例是相對于同一個Component而言的,不同的Component獲取到的實例將會是不一樣的。

    自定義Scope

    既然一個沒有scope的component不可以依賴一個有scope的組件component,那么我們必然需要自定義scope來去注解自己的Component了,定義方法如下:

    @Documented @Scope @Retention(RetentionPolicy.RUNTIME) public @interface FragmentScoped { }

    定義出來的FragmentScoped在使用上和Singleton是一樣的,那它和Singleton除了是不一樣的注解之外,還有什么不一樣呢?答案是沒有!我們自定義的scope和Singleton并沒有任何不一樣,不會因為Singleton是java自帶的注解就會有什么區(qū)別。

    那么,這個scope的設(shè)定是為了什么呢?

    scope的作用

    scope除了修飾provide方法可以讓我們獲得在同一個Component實例范圍內(nèi)的單例之外,主要的作用就是對Component和Moduld的分層管理以及依賴邏輯的可讀性。
    這里借用一個網(wǎng)絡(luò)上的圖片說明:

    ApplicationComponent一般會用singleton注解,相對的,它的Module中provide方法也只能用singleton注解。UserComponent是用UserSCope能直接使用ApplicationModule嗎?不能!因為他倆的scope不一致,這就是這個設(shè)定帶來的好處,防止不同層級的組件混亂。另外,因為有了scope的存在,各種組件的作用和生命周期也變得可讀起來了

    Lazy注入

    有時可能會需要延遲獲取一個實例。對任何綁定的 T,可以構(gòu)建一個 Lazy 來延遲實例化直至第一次調(diào)用 Lazy 的 get() 方法。注入之后,第一次get的時會實例化出 T,之后的調(diào)用都會獲取相同的實例。

    public class MainActivity extends AppCompatActivity implements MainView {// 懶加載@InjectLazy<MainPresenter> mPresenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MainPresenterComponent component = DaggerMainPresenterComponent.builder().mainPresenterModule(new MainPresenterModule(this)).applicationComponent(((DemoApplication) getApplication()).getAppComponent()).build();component.inject(this);Log.d("Hans", mPresenter.get().toString()); // 實例化MainPresenterLog.d("Hans", mPresenter.get().toString()); // 跟上次獲取的實例是同一個實例} }

    Provider注入

    跟Lazy注入不一樣的是,有時候我們希望每次調(diào)用get的時候,獲取到的實例都是不一樣的,這時候可以用Provider注入

    public class MainActivity extends AppCompatActivity implements MainView {// Provider@InjectProvider<MainPresenter> mPresenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MainPresenterComponent component = DaggerMainPresenterComponent.builder().mainPresenterModule(new MainPresenterModule(this)).applicationComponent(((DemoApplication) getApplication()).getAppComponent()).build();component.inject(this);Log.d("Hans", mPresenter.get().toString()); // 實例化MainPresenterLog.d("Hans", mPresenter.get().toString()); // 獲取新的MainPresenter實例} }

    Qualifiers注入

    到目前為止,我們的demo里,Moduld的provide返回的對象都是不一樣的,但是下面這種情況就不好處理了:

    @Module public class ApplicationModule {......// 返回ServerApi實例@ProvidesServerApi provideServerApiA(Context context) {return new ServerApiImplA(context);}// 返回ServerApi實例@ProvidesServerApi provideServerApiB(Context context) {return new ServerApiImplB(context);} }

    provideServerApiA和provideServerApiB返回的都是ServerApi,Dagger是無法判斷用哪個provide方法的。這時候就需要添加Qualifiers了:

    @Module public class ApplicationModule {......@Provides@Named("ServerApiImplA")ServerApi provideServerApiA(Context context) {return new ServerApiImplA(context);}@Provides@Named("ServerApiImplB")ServerApi provideServerApiB(Context context) {return new ServerApiImplB(context);} }

    通過這樣一個限定,就能區(qū)分出2個方法的區(qū)別了,當然,在使用過程中,也同樣要指明你用哪個name的實例,Dagger會根據(jù)你的name來選取對應(yīng)的provide方法:

    public class MainPresenter {private MainView mMainView;private ServerApi mServerApi;@Injectpublic MainPresenter(MainView mainView, @Named("ServerApiImplA") ServerApi serverApi) {this.mMainView = mainView;this.mServerApi = serverApi;} }

    除了用Named注解,你也可以創(chuàng)建你自己的限定注解:

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

    編譯時驗證

    Dagger 包含了一個注解處理器(annotation processor)來驗證模塊和注入。這個過程很嚴格而且會拋出錯誤,當有非法綁定或綁定不成功時。下面這個例子缺少了 Executor:

    @Module class DripCoffeeModule {@Provides Heater provideHeater(Executor executor) {return new CpuHeater(executor);} }

    當編譯時,javac 會拒絕綁定缺少的部分:

    [ERROR] COMPILATION ERROR : [ERROR] error: java.util.concurrent.Executor cannot be provided without an @Provides-annotated method.

    可以通過給方法 Executor 添加@Provides注解來解決這個問題,或者標記這個模塊是不完整的。不完整的模塊允許缺少依賴關(guān)系

    @Module(complete = false) class DripCoffeeModule {@Provides Heater provideHeater(Executor executor) {return new CpuHeater(executor);} }

    小結(jié)

    第一次接觸用Dagger框架寫的代碼時候,如果不了解各種注解作用的時候,那真會有一臉懵逼的感覺,而且單看文章,其實還是很抽象,建議大家用Dagger寫個小demo玩玩,很快就上手了,這里提供幾個使用Dagger的栗子,希望可以幫助大家上手Dagger

    • Dagger demo
    • 谷歌官方 MVP+Dagger2 Demo

    轉(zhuǎn)載于:https://www.cnblogs.com/hanschen-coder/p/6528817.html

    總結(jié)

    以上是生活随笔為你收集整理的依赖注入利器 - Dagger ‡的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。