1. 程式人生 > >使用Dagger2建立的第一個小例子

使用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方法的返回值。

最後測試程式的執行結果為: