使用Dagger2建立的第一個小例子
將Dagger系列的咖啡壺例子再做一下簡化,作為Dagger2的入門的第一個小例子。
場景描述:有一個電水壺,它使用一個加熱器來燒水。電水壺具備的功能有:開始加熱(on方法),結束加熱(off方法),倒水(brew方法)。
正確使用Dagger2要按照以下5個步驟來進行:
1.確定依賴物件和被依賴物件
本例中,水壺是依賴物件(dependent object),加熱器是被依賴物件(dependent object’s dependency),而與此同時,加熱器本身並不依賴誰,所以它是一個獨立的個體(independent model)。
加熱器:src/bean/Heater.java
public class Heater { private boolean isHot; public void on(){ System.out.println("開始燒開水啦"); isHot = true; } public void off(){ System.out.println("關閉加熱器"); isHot = false; } public boolean isHot(){ return isHot; } }
電水壺:src/bean/Kettle.java
public class Kettle { private Heater heater;//電水壺依賴於加熱器 public Kettle(Heater heater) { super(); this.heater = heater; } public void on(){ heater.on(); } public void off(){ heater.off(); } public void brew(){ if(heater.isHot()){ System.out.println("倒一杯開水"); } } }
2.建立@Module類
Module類的作用就是提供各種方法,來返回滿足依賴關係的物件。這些方法需要新增上@Provides註解。
src/module/KettleModule.java
@Module public class KettleModule { @Singleton @Provides Heater providesHeater(){ return new Heater(); } @Singleton @Provides Kettle providesKettle(Heater heater){ return new Kettle(heater); } }
3.當有了@Module類,提供所需的依賴和被依賴物件,那麼我們就在需要的地方進行取用即可。取用的方式是通過@Inject註解。現在修改以下之前的Kettle類:
<pre name="code" class="java" style="font-size: 18px;">public class Kettle {
private Heater heater;//電水壺依賴於加熱器
<span style="color:#ff6666;">@Inject</span>
public Kettle(Heater heater) {
super();
this.heater = heater;
}
public void on(){
heater.on();
}
public void off(){
heater.off();
}
public void brew(){
if(heater.isHot()){
System.out.println("倒一杯開水");
}
}
}
唯一修改的就是為構造器添加了@Inject註解。Dagger2中,@Inject註解可以新增在構造器、方法和屬性本身的前面。本例就通過構造器進行注入。
4.建立一個介面,讓@Inject和@Module建立起聯絡
寫一個介面,並用@Component進行註解,該註解有一個屬性module,它用來指明與@Inject建立聯絡的將是哪一個(或哪一些)@Module類。如果@Inject和@Module匹配正確,那麼在介面中定義的方法的返回值物件,都將是被正確注入了依賴關係的物件了:
src/module/KettleComponent:
@Singleton
@Component(modules=KettleModule.class)
public interface KettleComponent {
Kettle providesKettle();
}
5.獲得第4步中宣告的介面物件的例項,進而獲得介面中定義方法的返回值
@Component介面的實現類由Dagger2自動生成。這個類的命名規範是Dagger字首加上@Component類的名稱,那麼本例中,這個類的名稱就是DaggerKettleComponent了。
寫一個測試類,測試一下注入的結果:
src/main/Test:
public class Test {
public static void main(String[] args) {
KettleComponent component = DaggerKettleComponent.builder().build();
Kettle kettle = component.providesKettle();
kettle.on();
kettle.brew();
kettle.off();
}
}
這裡一定要注意,DaggerKettleComponent類是Daager2根據註解自動生成的一個類。我們可以看一下這個類的原始碼,就知道為什麼要這麼呼叫才能生成一個KettleComponent物件了。
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerKettleComponent implements KettleComponent {
private Provider<Heater> providesHeaterProvider;
private Provider<Kettle> providesKettleProvider;
private DaggerKettleComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static KettleComponent create() {
return builder().build();
}
private void initialize(final Builder builder) {
this.providesHeaterProvider = ScopedProvider.create(KettleModule_ProvidesHeaterFactory.create(builder.kettleModule));
this.providesKettleProvider = ScopedProvider.create(KettleModule_ProvidesKettleFactory.create(builder.kettleModule, providesHeaterProvider));
}
@Override
public Kettle providesKettle() {
return providesKettleProvider.get();
}
public static final class Builder {
private KettleModule kettleModule;
private Builder() {
}
public KettleComponent build() {
if (kettleModule == null) {
this.kettleModule = new KettleModule();
}
return new DaggerKettleComponent(this);
}
public Builder kettleModule(KettleModule kettleModule) {
if (kettleModule == null) {
throw new NullPointerException("kettleModule");
}
this.kettleModule = kettleModule;
return this;
}
}
}
DaggerKettleComponent實現了KettleCommpoment介面,並重寫了providesKettle方法。
首先呼叫靜態方法builder是為了建立靜態內部類Builder類的物件,建立物件後呼叫方法kettleModule方法為Builder的kettleModule屬性賦值,隨後再呼叫靜態內部類Builder物件的build方法建立DaggerKettleComponent的物件。在DaggerKettleComponent構造器中會首先對靜態內部類Builder物件進行一下判空,然後呼叫initialize(builder)方法,利用這個靜態內部類Builder物件為自己的兩個屬性賦值:providesHeaterProvider屬性和providesKettleProvider屬性。並且providesKettleProvider屬性值的建立要依賴於providesHeaterProvider屬性值。隨著providesHeaterProvider屬性和providesKettleProvider屬性初始化完畢,DaggerKettleComponent物件也就建立完畢了。當呼叫providesKettle方法的時候,返回的是providesKettleProvider的get方法的返回值。
最後測試程式的執行結果為: