---
##概述
依賴注入(Dependency Injection),簡稱DI,又叫控制反轉(Inversion of Control),簡稱IOC。Dagger2就是DI框架的一個例子。
---
##作用
將各層的對象以松耦合的方式組織在一起,解耦,各層對象的調用完全面向接口。
---
##提供依賴的兩種方式
###使用@Inject注解構造器
```javaclass Thermosiphon implements Pump {private final Heater heater;@InjectThermosiphon(Heater heater) {this.heater = heater;}}```
###使用@Module```java@Moduleclass DripCoffeeModule {@Provides static Heater provideHeater() {return new ElectricHeater();}@Provides static Pump providePump(Thermosiphon pump) {return pump;}}```**使用@Module替代@Inject的情況有:**-依賴是一個接口,不能使用構造器。-依賴是第三方類,不能添加@Inject注解。-依賴在使用前需要被配置。---##注入依賴的兩種方式使用@Inject和@Provides注解的類對象組成了一個有向圖(graph),該圖的頂點(vertex)由它們的依賴參數連接。我們可以通過@Component注解的接口來訪問這個有向圖。我們將Module傳遞給@Component的modile參數,Dagger2負責生成一個該接口的實現類,事實上構建一個Component的過程就是在構建一個graph。任何具有默認構造器的Module都不需要顯示地設置,builder會自動的創建Module。```javaCoffeeShop coffeeShop = DaggerCoffeeShop.builder().dripCoffeeModule(new DripCoffeeModule()).build();```可簡化成:```javaCoffeeShop coffeeShop = DaggerCoffeeShop.builder().build();```如果所需的依賴不需要構造Module就能提供(@Provides方法是靜態的),那么實現類會提供一個create()方法來快速的獲取一個Component實例。```javaCoffeeShop coffeeShop = DaggerCoffeeShop.create();```Component中可以可以包含兩種方法。分別為:-Provision Mothod-Members-injection MethodProvision Method沒有參數并且返回需要的類型。Members-injection Method一般沒有返回值,參數是需要注入成員變量的類(一般命名為inject)。---##依賴的來源-Module中通過@Provides注解的方法;Component通過@Component.modules直接引用,如果Module中通過@Module,include定義了子Module,也一并包括。-使用@Inject注解構造器的類(沒有使用@Scope或者@Scope同Component一致)-該Component依賴的Component的Provision Method-該Component本身-subComponent的未限定builder-以上依賴的Provider或者Lazy包裝類。-以上依賴的Lazy包裝類的Provider包裝類(如Provider)---##單例和作用域Component只會識別未加作用域或者作用域和自己一致的依賴。所以如果@Provids和可注入類加上了作用域,那么Component一定要加上作用域(和@Provide作用域一致的@Scope進行注解)。##Component的dependencies---Component不僅僅可以有modules也可以有dependencies。也就是依賴其他的Component。```java@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)@PerActivitypublic interface ActivityComponent {void inject(MainActivity mainActivity);}```注意:只有被依賴的Component中的Provisoin Method才會參與到該Component代表的有向圖構建。也就是說只有Provison Method返回的依賴才可以被初始化。---##\#SubComponentComponent可以依賴其他Component,dependence是實現其方式之一,也可以使用SubComponent。卻別在于dependence必須明顯的顯示依賴關系,而SubComponent不必明確的定義依賴關系。舉個例子說明一下:```java@Modulepublic class ModuleA {@Providespublic SomeClassA1 provideSomeClassA1() {return new SomeClassA1();}}@Modulepublic class ModuleB {@Providespublic SomeClassB1 provideSomeClassB1(SomeClassA1 someClassA1) {return new SomeClassB1(someClassA1);}}public class SomeClassA1 {public SomeClassA1() {}}public class SomeClassB1 {private SomeClassA1 someClassA1;public SomeClassB1(SomeClassA1 someClassA1) {this.someClassA1 = someClassA1;}}```通過 provideSomeClassB1 可以看出SomeClassB1依賴SomeClassA1先來看一下用dependence的方式實現```javapublic class ComponentDependency {@Component(modules = ModuleA.class)public interface ComponentA {SomeClassA1 someClassA1();}@Component(modules = ModuleB.class, dependencies = ComponentA.class)public interface ComponentB {SomeClassB1 someClassB1();}public static void main(String[] args) {ModuleA moduleA = new ModuleA();ComponentA componentA = DaggerComponentDependency_ComponentA.builder().moduleA(moduleA).build();ModuleB moduleB = new ModuleB();ComponentB componentB = DaggerComponentDependency_ComponentB.builder().moduleB(moduleB).componentA(componentA).build();}}```SomeClassB1依賴SomeClassA1,ComponentB必須明確的定義dependencies,而ComponentA不需要聲明ModuleB(modules)。SubComponent實現方式:```javapublic class SubComponent {@Component(modules = {ModuleA.class, ModuleB.class})public interface ComponentA {ComponentB componentB(ModuleB moduleB);}@Subcomponent(modules = ModuleB.class)public interface ComponentB {SomeClassB1 someClassB1();}public static void main(String[] args) {ModuleA moduleA = new ModuleA();ModuleB moduleB = new ModuleB();ComponentA componentA = DaggerSubComponent_ComponentA.builder().moduleA(moduleA).moduleB(moduleB).build();ComponentB componentB = componentA.componentB(moduleB);}}```SomeClassB1依賴SomeClassA1,ComponentB不需要聲明依賴,,而ComponentA則需要聲明ModuleB(modules),并且ComponentA必須返回@Subcomponent。---##\#可釋放的引用使用 Scope 注解時,Component 會間接持有綁定的依賴實例的引用,也就是說實例在 Component 還存活時無法被回收。這時可以用@CanReleaseReferences標記 Scope 注解:```java@Documented@Retention(RUNTIME)@CanReleaseReferences@Scopepublic @interface MyScope {}```然后在 Application 中注入ReleasableReferenceManager對象,在內存不足時調用releaseStrongReferences()方法把 Component 間接持有的強引用變為弱引用。```javapublic class MyApplication extends Application {@Inject@ForReleasableReferences(MyScope.class)ReleasableReferenceManager myScopeReferences;@Overridepublic void onLowMemory() {super.onLowMemory();myScopeReferences.releaseStrongReferences();}...}```這樣在內存不足時,DaggerCoffeeShop 間接持有的變 實例為弱引用,如果沒有其他對象使用的話就可以被回收。##\#Lazy (延遲注入)有時我們想注入的依賴在使用時再完成初始化,加快加載速度,就可以使用注入Lazy。只有在調用 Lazy的 get() 方法時才會初始化依賴實例注入依賴。```javapublic class Main {@InjectLazy lazyMaker;public void goWork() {...lazyMaker.get(); // lazyMaker.get() 返回 CoffeeMaker 實例...}}```##\#Provider 注入有時候不僅僅是注入單個實例,我們需要多個實例,這時可以使用注入Provider,每次調用它的 get() 方法都會調用到 @Inject 構造函數創建新實例或者 Module 的 provide 方法返回實例。```javapublic class Main {@InjectProvider providerMaker;public void goWork() {...List makerList = new ArrayList(num);for (int i = 0; i < num; i ++) {makerList.add(providerMaker.get());}return makerList;...}}```----##\#限定符(Qualifiers)解決接口或者抽象類不足以描述一個依賴的問題```java@Qualifier@Retention(RetentionPolicy.RUNTIME)public @interface BananaFruit {}``````java@Qualifier@Retention(RetentionPolicy.RUNTIME)public @interface AppleFruit {}```加在所有你想返回確切class的地方。