初識dagger(一)

依賴注入

依賴注入:在項目開發中,常見一個類的實例依賴另外一個類實例的狀況 如java

public  class Man(){
	prviate Car car;
	public Man(){
		car=new Car();
	}
}
複製代碼

常見的依賴方式基於構造方法,set設置等緩存

依賴注入是控制反轉的一種表現形式,被依賴的對象(Car)再也不由 依賴對象(Man)主動建立 ,而是由第三方容器去建立,而後注入到依賴對象(man)的過程,下降代碼耦合性bash

集成與使用

在build.gradle中添加依賴:ide

dependencies {
    ...
    implementation 'com.google.dagger:dagger:2.13'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.13'
}
複製代碼

藉助上面的場景進行應用測試

Car相關代碼 因爲Car須要被注入,在構造方法上增長 @Inject 註解gradle

public class Car {
  private CarDipan carDipan;

  @Inject
  public Car() {
  }

  public void pao() {
    System.out.println("跑起來");
  }
}
複製代碼

Man相關代碼 在Car變量上聲明 @Inject 註解ui

public class Man {
  @Inject
  Car car;

  public Man() {
    //該行代碼後面講到
    DaggerManComponent.create().inject(this);
  }

  public void kaiche() {
    car.pao();
  }
}
複製代碼

此時依賴和被依賴的類都建立好了,還缺乏一個紐帶把他們鏈接起來,紐帶就是 @Component
@Component 註解須要做用到接口或者抽象類上,添加抽象方法,參數是須要注入依賴的類,會自動生成以Dagger開頭的實現類 在Man的構造方法中進行注入 DaggerManComponent.create().inject(this); (可能會報找不到該類,須要rebuild下) ManComponent代碼以下this

@Component
interface ManComponent {
  void inject(Man man);
}

複製代碼

測試代碼google

public class DaggerTest {
  public static void main(String[] args) {
    Man man = new Man();
    man.kaiche();
  }
}
複製代碼

Module和Provides註解

有一些第三方庫,咱們沒法修改源碼,即沒法用@Inject去註解構造方法。這時候就須要@Module和@Provides註解spa

  • @Module 註解到類上,表示這個類能夠做爲一個模塊去引入到被@Component註解的接口上,規定用@Module註解的類名以Module作後綴
  • @Provides用於被@Module標註類的方法中,規定用provide做爲前綴
    假設Man對象包含一個FangZi對象,該對象構造方法沒法用@Inject註解標註,那麼能夠提供如下類
@Module
public class FangModule {
  @Provides
  public Fang provideFang() {
    return new Fang();
  }
}
複製代碼

對應的ManComponent類也須要修改

@Component(modules = FangModule.class)
interface ManComponent {
  void inject(Man man);
}
複製代碼

這樣Man裏面的房子屬性就會成功注入。被注入的屬性必定要用@Inject註解
Module類的構造方法能夠帶有參數,須要注意的是當Module類有帶有參數的構造方法時, DaggerManComponent不會有Create方法,須要經過DaggerManComponent.builder().fangModule(new FangModule(參數)).build()手動傳入module對象

Bind註解

Bind註解和Provides注意相似 ,也是放到被Module類的方法上,不一樣的是Bind註解的方法是抽象方法,參數類型是返回值類型的子類。 用於注入某個接口或者抽象類時,能夠獲取他的實現子類。或者能夠說將一種類型轉換成他的父類或接口,只暴露父類或接口的方法

BindModule.java

@Module
public abstract class BindModule {
  @Binds
  public abstract Manger bindManager(ManagerImpl manager);
  
  public static abstract class Manger {
    public abstract String getName();
  }

  public static class ManagerImpl extends Manger {
    @Inject
    public ManagerImpl() {
    }

    @Override public String getName() {
      return "我是ManagerImpl";
    }
  }
}
Man.java

public class Man {

  @Inject
  BindModule.Manger manger;//這是獲取的時他的子類MangerImpl

  public Man() {
    DaggerManComponent.create().inject(this);
  }

  public void run() {
    System.out.println(manger.getName());
  }
}
複製代碼

Named、Singleton和Reusable

@Named 別名註解 和@Provides配合使用 好比我有兩套房子,可是返回值都是房子 若是不用@Named註解,dagger不知道我們要哪一個房子,就會迷失,這時就須要起一個別名

@Module
public class FangModule {

  @Named("北三環")
  @Provides
  public Fang provideFang() {
    return new Fang("北三環");
  }
  @Named("西四環")
  @Provides
  public Fang provideFang2() {
    return new Fang("西四環");
  }
}
複製代碼

在獲取房子是就必須註明@Named 表示 要哪個

public class Man {
  @Inject
  Car car;
  @Named("北三環")
  @Inject
  Fang fang1;
  @Named("西四環")
  @Inject
  Fang fang2;
}
複製代碼

@Qualifier 元註解 註解在@Named上 咱們能夠用 Qualifier自定義和 @Named功能相同的 註解
@Singleton 單例註解 在一個Component組件中單例 Singleton標註在Component上 和 Provides標註的方法或者標註在要注入的類上。 實現機制 是經過DoubleCheck來保證單例,在生成的DaggerManComponent類的初始化中,會把Provider轉換爲DoubleCheck 在DoubleCheck的get方法中保證明例惟一

@Module
public class FangModule {
  @Singleton
  @Provides
  public Fang provideFang() {
    return new Fang("北三環");
  }
}
複製代碼
@Singleton
@Component(modules = FangModule.class)
interface ManComponent {
  void inject(Man man);
}
複製代碼

@Scope 元註解 註解在@Singleton 咱們能夠用 @Scope自定義和 @Singleton功能相同的 註解
@Reusable 註解 有時咱們爲了限制對象的建立次數,使用時能夠從緩存中獲取對象,可使用該註解 該註解標註在 Provides標註的方法或者標註在要注入的類上。 該機制會把Provider轉換爲SingleCheck來 使用SingleCheck來保證若是無對象會建立對象 若是有則會從緩存中獲取

@Module
public class FangModule {
  @Reusable
  @Provides
  public Fang provideFang() {
    return new Fang("北三環");
  }
}
複製代碼
@Component(modules = FangModule.class)
interface ManComponent {
  void inject(Man man);
}  
複製代碼

Lazy和Provider

Lazy 有時候咱們不想運行時就把類建立好,而是在須要的時候建立類,這是就能夠經過Lazy包裝要被注入的成員 ,使用時經過get方式獲取

public class Man {
  @Inject
  Lazy<Car> car;

  public Man() {
    DaggerManComponent.create().inject(this);
  }

  public void kaiche() {
    car.get().pao();
  }
} 
複製代碼

Provider 有時咱們 須要建立類的多個實例,能夠經過Provider包裝要被注入的成員,每次執行get則會建立一個新的實例

IntoSet和IntoMap註解

IntoSet須要和Provides或Bind一塊兒使用,咱們知道在Module中若是有兩個方法返回值會致使依賴迷失,須要用Named註解起別名。 可是若是這些方法被@IntoSet註解修飾,相同的返回值產生的對象會被放到同一個Set集合中。同時注入該類對象時,須要用Set去包裝

FangModule.java

@Module
public class FangModule {
  @IntoSet
  @Provides
  public Fang provideFang1() {
    return new Fang("國貿");
  }

  @IntoSet
  @Provides
  public Fang provideFang2() {
    return new Fang("望京");
  }
}

Man.java

public class Man {
  @Inject
  Set<Fang> fangs;

  public Man() {
    DaggerManComponent.builder().fangModule(new FangModule()).build().inject(this);
  }

  public void run() {
    fangs.forEach(Fang::get);
  }
}
複製代碼

IntoMap和IntoSet相似,不過是將發返回的對象放入到map集合中。用IntoMap註解時, 必須指明Key.使用 @IntKey/ @LongKey/@StringKey註解 也可使用@MapKey元註解,自定義Key註解

相關文章
相關標籤/搜索