簡介
dagger2:
https://github.com/google/dagger
dagger:
https://github.com/square/dagger
compile 'com.google.dagger:dagger:2.11'//2017-9-17最新版本為【2.11】
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'//dagger-compiler為編譯時期生成代碼等相關的類庫
Dagger2 是一個Android依賴注入框架,由谷歌開發,最早的版本Dagger1 由Square公司開發。
依賴注入框架主要用於模塊間解耦,提高代碼的健壯性和可維護性。
Dagger 這個庫的取名不僅僅來自它的本意“匕首”,同時也暗示了它的原理。Jake Wharton 在對 Dagger 的介紹中指出,Dagger 即 DAG-er,這里的 DAG 即數據結構中的 DAG:有向無環圖(Directed Acyclic Graph)。也就是說,Dagger 是一個基於有向無環圖結構的依賴注入庫,因此Dagger的使用過程中不能出現循環依賴。
Android開發從一開始的MVC框架,到MVP,到MVVM,不斷變化。現在MVVM的
data-binding還在實驗階段,傳統的MVC框架Activity內部可能包含大量的代碼,難以維護,現在主流的架構還是使用MVP的方式。但是 MVP 框架也有可能
在Presenter中集中大量的代碼,引入DI框架Dagger2 可以實現
Presenter 與 Activity 以及 Presenter 和其它業務邏輯之間的解耦,提高模塊化和可維護性。
依賴注入就是將調用者需要的另一個對象實例不在調用者內部實現,而是通過一定的方式從外部傳入實例,解決了各個類之間的耦合。
那么這個外部,到底指的是哪里,如果指的是另一個類,那么,另一個類內部不就耦合了?能不能有一種方式,
將這些構造的對象放到一個容器中,具體需要哪個實例時,就從這個容器中取就行了
。這樣,
類的實例和使用就不在有聯系了,而是通過一個容器將他們聯系起來
,實現了解耦。這個容器,便是Dagger2。
Dagger2的原理是:
在【編譯期】生成相應的依賴注入代碼
。這也是和其他依賴注入框架不同的地方,
其他框架是在【運行時】通過【反射】獲取【注解內容】
,影響了運行效率。
【Dagger1】
Dagger1可以說是如今Android上最流行的依賴注入框架。它是由Square公司受到Guice啟發創建的。
基本特點:
- 多個注入點:依賴,通過injected
- 多種綁定方法:依賴,通過provided
- 多個modules:實現某種功能的綁定集合
- 多個對象圖: 實現一個范圍的modules集合
Dagger1是在編譯的時候實行綁定,不過也用到了反射機制。但這個反射不是用來實例化對象的,而是用於圖的構成。Dagger會在運行的時候去檢測是否一切都正常工作,所以使用的時候會付出一些代價:偶爾會無效和調試困難。
【Dagger2】
Dagger2是Dagger1的分支,由谷歌公司接手開發。Dagger2是受到AutoValue項目的啟發。剛開始,Dagger2解決問題的基本思想是:利用生成和寫的代碼混合達到看似所有的產生和提供依賴的代碼都是手寫的樣子。
如果我們將Dagger2和1比較,他們兩個在很多方面都非常相似,但也有很重要的區別,如下:
- 再也沒有使用反射:圖的驗證、配置和預先設置都在編譯的時候執行。
- 容易調試和可跟蹤:完全具體地調用提供和創建的堆棧
- 更好的性能:谷歌聲稱他們提高了13%的處理性能
- 代碼混淆:使用派遣方法,就如同自己寫的代碼一樣
當然所有這些很棒的特點都需要付出一個代價,那就是缺乏靈活性,例如:Dagger2沒用反射所以沒有動態機制。
【JSR-330】
為了最大程度的提高代碼的復用性、測試性和維護性,java的依賴注入為注入類中的使用定義了一整套注解(和接口)標准。Dagger1和Dagger2(還有Guice)都是基於這套標准,給程序帶來了穩定性和標准的依賴注入方法。
使用dagger2的好處
好處:
- 增加開發效率、省去重復的簡單體力勞動
首先new一個實例的過程是一個重復的簡單體力勞動,dagger2完全可以把new一個實例的工作做了,因此我們把主要精力集中在關鍵業務上、同時也能增加開發效率上。
省去寫單例的方法,並且也不需要擔心自己寫的單例方法是否線程安全,自己寫的單例是懶漢模式還是餓漢模式,因為dagger2都可以把這些工作做了。 - 更好的管理類實例
每個app中的ApplicationComponent管理整個app的全局類實例,所有的全局類實例都統一交給ApplicationComponent管理,並且它們的生命周期與app的生命周期一樣。
每個頁面對應自己的Component,頁面Component管理着自己頁面所依賴的所有類實例。
因為Component,Module,整個app的類實例結構變的很清晰。 - 解耦
假如不用dagger2的話,一個類的new代碼是非常可能充斥在app的多個類中的,假如該類的構造函數發生變化,那這些涉及到的類都得進行修改。設計模式中提倡把容易變化的部分封裝起來。
解耦還有個好處,就是方便測試,若需要替換為網絡測試類,只需要修改相應的Module即可。
我們用了dagger2后。
- 假如是通過用Inject注解標注的構造函數創建類實例,則即使構造函數變的天花亂墜,我們基本上都不需要修改任何代碼。
- 假如是通過工廠模式Module創建類實例,Module其實就是把new類實例的代碼封裝起來,這樣即使類的構造函數發生變化,只需要修改Module即可。
GitHub中的介紹
A fast
dependency injector for Android and Java.
適用於Android和Java的快速依賴注入器。
【About Google's Fork】
Dagger 2 is a compile-time evolution approach to dependency injection. Taking the approach started in Dagger 1.x to its ultimate conclusion, Dagger 2.x eliminates all reflection, and improves code clarity by removing the traditional ObjectGraph/Injector in favor of user-specified @Component interfaces.
Dagger 2是
接近依賴注入的一種編譯時進化。采用Dagger 1.x開始的方式達成
最終結論,Dagger 2.x
消除了所有的反射,並通過刪除傳統的ObjectGraph / Injector來改善代碼
清晰度,並以用戶指定的@Component接口來取代。
evolution [ˌɛvəˈluʃən, ˌivə-] n. 演變; 進化; 發展;
approach [əˈproʊtʃ] vt.接近,走近,靠近; vt.接近; 着手處理; 使移近; n. 方法; 途徑; 接近;
in favor of 贊成[支持](某人或某事物); 以…取代; (支票) 以某人[某部門]為受款人;
This github project represents the Dagger 2 development stream. The earlier project page (Square, Inc's repository) represents the earlier 1.0 development stream. Both versions have benefitted from strong involvement from Square, Google, and other contributors.
這個github項目代表了Dagger 2開發流。較早的項目頁面(Square,Inc的存儲庫)代表較早的1.0開發流。這兩個版本都
受益於Square、Google和其他貢獻者的強烈
參與。
Dagger is currently in active development, primarily internally at Google, with regular pushes to the open-source community. Snapshot releases are auto-deployed to sonatype's central maven repository on every clean build with the version HEAD-SNAPSHOT.
Dagger 目前正在積極發展,主要是內部在谷歌,定期push到開源社區。快照版本將自動部署到sonatype的中央maven存儲庫,每個干凈的版本與版本HEAD-SNAPSHOT。
【Documentation】
You can find the dagger documentation here which has extended usage instructions and other useful information. Substantial usage information can be found in the API documentation.
您可以在這里找到
擴展使用說明和其他有用信息的匕首文檔。可以在API文檔中找到
實質的使用信息。
You can also learn more from the original proposal, this talk by Greg Kick, and on the dagger-discuss@googlegroups.com mailing list.
您還可以從原始
提案中了解更多信息,Greg Kick的此演講以及**郵件列表。
【Installation】
You will need to include the dagger-2.x.jar in your application's runtime. In order to activate code generation and generate implementations to manage your graph you will need to include dagger-compiler-2.x.jar in your build at compile time.
您可能需要將dagger-2.x.jar包含在應用程序的運行時中。為了激活代碼生成器並生成實現以管理圖形,您將需要在編譯時將dagger-compiler-2.x.jar包含在構建中。
Gradle配置
1、在項目的build.gradle中添加:
dependencies {
classpath 'com.android.tools.build:gradle:2.3.1'//每個Android項目默認都會帶的
//PS:在新版本中千萬不要加這些,日了狗了,加上去之后反而不會生成DaggerXXXComponent。
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'//這個是需要我們手動添加的,apt是用於自動生成代碼來進行依賴注入的
}
android-apt是Gradle編譯器的插件,根據其官方文檔,主要兩個目的:
- 編譯時使用該工具,最終打包時不會將該插件打入到apk中。
- 能夠根據設置的源路徑,在編譯時期生成相應代碼。
2、在module的build.gradle中添加:
apply plugin: 'com.android.application'//每個Android項目默認都會帶的。在build.gradle的第一行
//PS:在新版本中千萬不要加這些,日了狗了,加上去之后反而不會生成DaggerXXXComponent。
apply plugin: 'com.neenbedankt.android-apt'//apt支持
3、在module的build.gradle中添加:
compile 'com.google.dagger:dagger:2.x'
annotationProcessor 'com.google.dagger:dagger-compiler:2.x'//dagger-compiler為編譯時期生成代碼等相關的類庫
在android-apt的文檔中,也推薦使用這種方式。因為,編譯時期生成代碼的類庫在運行期並不需要,那么將其分為兩個庫:運行類庫
butterknife/
dagger和 編譯器生成代碼類庫
butterknife-compiler/
dagger-compiler。那么在打包時,就不需要將
butterknife-compiler/
dagger-compiler打入其中,減小APK 的大小。
4、其他配置
If you're using classes in
dagger.android you'll also want to include:
compile 'com.google.dagger:dagger-android:2.x'
compile 'com.google.dagger:dagger-android-support:2.x' // if you use the support libraries
annotationProcessor 'com.google.dagger:dagger-android-processor:2.x'
If you're using a version of the Android gradle plugin below 2.2, see https://bitbucket.org/hvisser/android-apt .
If you're using the
Android Databinding library, you may want to increase the number of errors that
javac will print. When Dagger prints an error, databinding compilation will halt and sometimes print more than 100 errors, which is the default amount for javac. For more information, see
Issue 306.
如果您正在使用Android Databinding庫,您可能需要增加javac將打印的錯誤數量。當Dagger打印錯誤時,數據綁定編譯將停止,有時會打印超過100個錯誤,這是javac的默認值。 有關詳細信息,請參閱問題306。
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xmaxerrs" << "500" // or whatever number you want
}
}
一個簡單的Dagger2示例
通過Dagger2的目的是將程序分為三個部分:
- - 實例化部分:對象的實例化。類似於容器,將類的實例放在容器里。
- - 調用者:需要實例化對象的類。
- - 溝通橋梁:利用Dagger2中的一些API 將兩者聯系。
實例化部分Module:
@Module//作為實例對象的容器
public class MainModule {
String name;
public MainModule(String name) {
this.name = name;
}
@Provides//標注能夠提供實例化對象的方法。方法名字可以隨意,但建議以provider開頭
Person providerPerson() {//先判斷Module中是否有提供該對象實例化的方法(根據返回值類型及@Provides注解來判斷),如果有則注入返回的對象
return new Person(name);//如果沒有,則查找Inject注解的構造函數。如果有,則注入使用此構造方法創建的對象
//如果@Provides方法或@Inject構造方法需要參數,則先按同樣的步驟初始化參數。若存在參數但無法初始化參數,則編譯不通過。
}
}
溝通橋梁部分Component:
@Component(modules = MainModule.class) //作為橋梁,溝通調用者和依賴對象庫
public interface MainComponent {
void inject(MainActivity activity);//定義注入的方法。方法名隨意,但建議以inject開頭
}
調用者Actvity:
public class MainActivity extends AppCompatActivity {
@Inject Person person;//標注需要注入的對象。注意:使用@Inject時,不能用private修飾成員屬性
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerMainComponent.builder().mainModule(new MainModule("白乾濤")).build().inject(this);
Log.i("bqt", person.name);//包青天。如果去掉providerPerson上的【@Provides】注解,則會調用Person具有@Inject的構造方法
}
}
看一下Person類:
public class Person {
public String name;
@Inject
public Person() {
name = "默認的名字";
}
public Person(String name) {
this.name = name;
}
}
總結:dagger2依賴注入的步驟
dagger2進行一次依賴注入的步驟:
根據@Inject注解,查找需要依賴注入的對象。注意:使用@Inject注解時,不能用private修飾成員屬性或構造方法,否則編譯不通過,提示如下錯誤:
如果以上兩種方式都沒有提供,則
編譯不通過,提示如下錯誤:
Error:(16, 25) 錯誤: Dagger does not support injection into private fields
Error:(54, 10) 錯誤: Dagger does not support injection into private constructors
- 先判斷Module中是否有提供該對象實例化的方法(即:根據返回值類型及是否@Provides注解來判斷),如果有:
- 若不存在參數,則直接初始化該類實例,此次依賴注入到此結束!
- 若存在參數,則從**步驟1**開始依次初始化每個參數(PS:若存在參數但無法初始化參數,則編譯不通過)
- 若不存在創建類方法,則查找Inject注解的構造函數,看構造函數是否存在參數
- 若不存在參數,則直接初始化該類實例,此次依賴注入到此結束!
- 若存在參數,則從**步驟1**開始依次初始化每個參數(PS:若存在參數但無法初始化參數,則編譯不通過)
- PS:若存在多個@Inject注解的構造函數,需要使用@Qulifier限定符,否則編譯不通過,提示如下錯誤:
Error:(51, 9) 錯誤: Types may only contain one @Inject constructor.
> java.lang.IllegalStateException: Found multiple @Inject constructors: [Person(), Person(java.lang.String)]
Error:(44, 7) 錯誤: com.bqt.dagger.Person cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method.
其實這個步驟是一個遞歸的過程,並且在查找類的實例的過程中Module的級別要高於Inject。
PS:本來通過@Inject就可以完成依賴注入了,為什么還要用到Module類來提供依賴呢?
這是為了適配
第三方類庫中的類(我們沒辦法給修改這些類),或那些
沒有
提供
構造方法的類(
比如單例模式的類、系統類、框架類,比如Activity,其構造方法一般都是私有的),我們無法給這些類的構造方法添加@Inject標注,只能通過
Module類來提供依賴。
Component的組織方式
假如一個app中只有一個Component,那這個Component是很難維護、並且變化率是很高,很龐大的,就是因為Component的職責太多了導致的。所以就有必要把這個龐大的Component進行划分,划分為粒度小的Component。
划分的規則建議是這樣的:
- 要有一個全局的Component,負責管理整個app的全局類實例,全局類實例是整個app都要用到的類的實例,這些類基本都是單例的
- 每個【頁面】對應一個Component,比如一個Activity頁面定義一個Component,一個Fragment定義一個Component。當然這不是必須的,有些頁面之間的依賴的類是一樣的,可以公用一個Component。
為什么以頁面為粒度來划分Component?
- 一個app是由很多個頁面組成的,從組成app的角度來看一個頁面就是一個完整的最小粒度了。
- 一個頁面的實現是要依賴各種類的,可以理解成一個頁面把各種依賴的類組織起來共同實現一個大的功能,每個頁面都組織着自己的需要依賴的類,一個頁面就是一堆類的組織者。
- 划分粒度不能太小了。假如使用mvp架構搭建app,划分粒度是基於每個頁面的m、v、p各自定義Component的,那Component的粒度就太小了,定義這么多的Component,管理、維護就很非常困難。
整體來說,在Android項目中,以頁面划分Component在管理、維護上面相對來說更合理。
Scope的真正用處就在於Component的組織:
- 更好的管理Component之間的組織方式,不管是依賴方式還是包含方式,都有必要用自定義的Scope注解標注這些Component,這些注解最好不要一樣,不一樣是為了能更好的體現出Component之間的組織方式。還有編譯器檢查有依賴關系或包含關系的Component,若發現有Component沒有用自定義Scope注解標注,則會報錯。
- 更好的管理Component與Module之間的匹配關系,編譯器會檢查 Component管理的Modules,若發現標注Component的自定義Scope注解與Modules中的標注創建類實例方法的注解不一樣,就會報錯。
- 可讀性提高,如用Singleton標注全局類,這樣讓程序猿立馬就能明白這類是全局單例類。
涉及到的注解介紹
單詞釋義
Dagger [ˈdæɡɚ] n. 匕首; 短劍; vt. 用劍刺;
Inject [ɪnˈdʒɛkt] vt.(給…)注射(葯物等);(給…)注射(液體);(給…) 添加;(給…)投入(資金);
Component [kəmˈpoʊnənt] n. 成分; 組分; 零件; [數] 要素; adj. 成分的; 組成的; 合成的; 構成的;
Module [ˈmɑ:dʒul] n. 模塊; 組件; (宇宙飛船上各個獨立的) 艙; 測量流水等的單位;
Scope [skoʊp] n.(處理、研究事務的)范圍; 眼界,見識; (活動或能力的)余地; 廣袤,地域; v.審視,仔細研究;
Singleton [ˈsɪŋɡəltən] n.一個,獨身,單獨;
Qualifier [ˈkwɑ:lɪfaɪə(r)] n.合格者,已取得資格的人; [語] 修飾語; 預選賽,資格賽;
【Inject】
用來標注所依賴的目標類的實例和所依賴的目標類的構造函數。帶有此注解的屬性或構造方法將參與到依賴注入中,Dagger2會實例化有此注解的類。
Identifies injectable constructors, methods, and fields. May apply to static as well as instance members. An injectable member may have any access modifier (private, package-private, protected, public). Constructors are injected first, followed by fields, and then methods. Fields and methods in superclasses are injected before those in subclasses. Ordering of injection among fields and among methods in the same class is not specified.
標識可注入的構造函數,方法和字段。可能適用於靜態和實例成員。可注射成員可以具有任何訪問修飾符。首先注入構造函數,后跟字段,然后是方法。超類中的字段和方法被注入到子類之前。沒有指定在同一類中的字段之間和方法之間的注入順序。
Injectable constructors are annotated with @Inject and accept zero or more dependencies as arguments. @Inject can apply to at most one constructor per class.
可注射構造函數用@Inject注釋,並接受零個或多個依賴關系作為參數。 @Inject可以每個類最多只能應用一個構造函數。
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})//方法,構造方法,字段
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface javax.inject.Inject {
}
【Module】
帶有此注解的類其實是一個簡單工廠模式,去作用就是創建對象。帶有此注解的類的方法基本都是創建類實例的方法,這些方法需要用@Provides注解,這些方法就是所提供的依賴,Dagger2會在該類中尋找實例化某個類所需要的依賴。
//Annotates a class that contributes to the object graph.
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})//類
public @interface dagger.Module {
/**
* Additional額外的、補充的 @Module-annotated classes from which this module is composed 組成.
* The de-duplicated復制出的 contributions of the modules in includes,
* and of their inclusions recursively遞歸地, are all contributed to the object graph.
*/
Class<?>[] includes() default {};//代表此Module依賴其他Module,效果和在Component中直接依賴多個Module一樣。
}
【Provides】
用來標注Module類中創建類實例的方法,這些方法就是所提供的依賴。
/**
* Annotates methods of a Module to create a provider method binding. The method's return type is bound to its returned value.
* The Component component implementation will pass dependencies to the method as parameters.
*/
@Documented
@Target({ElementType.METHOD})//方法
@Retention(RetentionPolicy.RUNTIME)
public @interface dagger.Provides {
Provides.Type type() default Provides.Type.UNIQUE;
public static enum Type {
UNIQUE, SET, SET_VALUES, MAP;
private Type() {
}
}
}
【Component】
帶有此注解的類是將Inject和Module聯系起來的橋梁。編譯后通過調用自動生成的DaggerXXX類的API,便可以從Module中獲取依賴,並將依賴注入到Inject中。通過
modules屬性可以把
多個
Module加入
此
Component中。
- dependencies代表需要哪一個Component提供依賴,擴展當前Component的支持的依賴。用起來有幾個注意事項。
- module代表通過哪一個Module提供依賴。
/**
* Annotates an interface or abstract class for which a fully-formed, dependency-injected
* implementation is to be generated from a set of modules.
* The generated class will have the name of the type annotated with @Component prepended with Dagger.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})//類
@Documented
public @interface dagger.Component {
Class<?>[] modules() default {};//指定此Component通過哪些Module獲取依賴
//A list of types that are to be used as <a href="#component-dependencies"> component dependencies </a>.
Class<?>[] dependencies() default {};//指定此Component依賴於哪些Component,擴展當前Component的支持的依賴
@Target({ElementType.TYPE})
@Documented
public @interface Builder {
}
}
【Qualifier】
限定符,用於區別不同的
對象以及提供
相應的對象實例的方法。Qualifier是一個元注解,用於注解其他注解,被注解的元素和@Named的作用完全一樣。
//Identifies qualifier annotations. Anyone can define a new qualifier.
@Target(ElementType.ANNOTATION_TYPE)//元注解
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface javax.inject.Qualifier {
}
【Named】
限定符,用於區別不同的對象以及提供相應的對象實例的方法。Named注解有一個String類型的屬性,所以可以直接傳遞值,但只能傳遞字符串。
注意:如果在一個字段上添加了Named注解(或任何用Qualifier注解標注的注解),那么必須能在Module中找到相應的提供對象的方法,否則報錯。
//String-based Qualifier.
@Qualifier//@Named注解就是被元注解@Qualifier注解的注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface javax.inject.Named {
String value() default "";//@Named可以直接傳遞值,但只能傳遞字符串
}
【Scope】
注解作用域。Scope是一個元注解,用於注解其他注解,被注解的元素和@Singleton的作用完全一樣。
用@Scope標注的注解的主要作用:
- 1、限定對象的作用范圍。可以使基於同一Component實例的Module中創建的對象具有單例效果。
比如我們用Scope注解標注一個自定義的名為MyScope的注解,假如在一個ComponentB前面加了@Myscope注解,那么如果對ComponentB管理的某個Module中的某個【ObjectA provideObjectA 】方法也加上@Myscope注解,那么Dagger2會在第一次使用該方法創建ObjectA時將它緩存起來,下次再需要提供ObjectA時,就直接使用緩存的對象,而不會再次創建新的ObjectA。如果沒有加@Myscope注解,則會每次都創建一個新的ObjectA對象。 - 2、組織Component
Identifies scope annotations. A scope annotation applies to a class containing an injectable constructor and governs how the injector reuses instances of the type. By default, if no scope annotation is present, the injector creates an instance (by injecting the type's constructor), uses the instance for one injection, and then forgets it. If a scope annotation is present, the injector may retain the instance for possible reuse in a later injection. If multiple threads can access a scoped instance, its implementation should be thread safe. The implementation of the scope itself is left up to the injector.
標識范圍注釋。 范圍注釋
適用於包含可注入構造函數的類,並
控制注射器如何
重用類型的實例。默認情況下,如果沒有范圍注釋,則注入器將創建一個實例(通過注入類型的構造函數),
使用該實例進行一次注入,然后將其忽略。 如果存在范圍注釋,注射器可以
保留實例以便在稍后的注射中可能重新使用。 如果
多個線程可以訪問作用域實例,其實現應該是線程安全的。 范圍本身的實現
由注射器決定。
Annotating scope annotations with @Scope helps the injector detect the case where a programmer used the scope annotation on a class but forgot to configure the scope in the injector. A conservative injector would generate an error rather than not apply a scope.
使用@Scope注釋范圍注釋有助於注入器
檢測程序員在類上使用范圍注釋但忘記配置注入器中的范圍
的情況。
保守的注射器會產生錯誤,而不是應用范圍。
@Target(ElementType.ANNOTATION_TYPE)//元注解
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface javax.inject.Scope {}
【Singleton】
作用為:標記為單例模式(這里有坑)。
注意,Singleton注解只是用Scope注解標注的一個普通的注解,其本身沒有單例功能。Singleton注解的作用和任何一個用Scope注解標注的注解的作用完全一樣。使用Singleton后之所以在某些情況下具有單例效果,更多的是其他方面的原因,而不僅僅是因為添加了Singleton注解的原因。
注意:
- 如果只在@Provides標注的方法上添加@Singleton注解(或者任何用@Scope標注的注解),而沒在相應的Component類上添加,則編譯失敗!
- 相反,如果只在Component類上添加,而不再相應的Module中用@Provides標注的方法上添加,則沒有任何效果!
//Identifies識別 a type that the injector only instantiates實例化 once. Not inherited.不可遺傳
@Scope//Singleton注解是被元注解@Scope注解的注解。
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface javax.inject.Singleton {}//如果在Module中使用了此注解,在Component上也要使用該注解,否則編譯失敗
【Subcomponent】
在需要父組件全部的提供對象,這時我們可以用包含方式而不是用依賴方式
//A subcomponent子組件 that inherits繼承 the bindings綁定 from a parent Component or Subcomponent.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)//元注解
@Documented
public @interface dagger.Subcomponent {
/**
* A list of classes annotated with Module whose bindings are used to generate the subcomponent implementation.
* Note that through the use of通過使用 【Module.includes】 the full set of modules used to implement the subcomponent
* may include more modules that just those listed here.
*/
Class<?>[] modules() default {};
@Target(TYPE)
@Documented
@interface Builder {}
}
2017-9-17
