這是 Dagger 2 的使用筆記,參考了 這篇文章 進行實作
使用 Car
& Wheel
兩種 class 當作範例
其相依關係是:
Activity -> Car -> Wheel
使用 @Inject
& @Component
使用 Constructor Injection
public class Wheel2 {
@Inject
public Wheel2() {}
public String getBrand(){
return "Bridgestone";
}
}
使用 Constructor Injection 建立 與 Wheel 的相依性
public class Car2 {
private Wheel2 wheel2;
@Inject
public Car2(Wheel2 wheel2) {
this.wheel2 = wheel2;
}
public String getWheelInfo(){
return "friction : " + wheel2.getBrand();
}
}
建立 Component
@Component
public interface BasicDaggerActivityComponent {
// 指定 inject 的 target Activity
void inject(BasicDaggerActivity activity);
}
在 Activity 啟用
public class BasicDaggerActivity extends AppCompatActivity {
@Inject
Car2 car2;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
DaggerBasicDaggerActivityComponent.create().inject(this);
// DaggerBasicDaggerActivityComponent 是依據 Component 建立出來的,需要先編譯過才會做出來
}
}
用 Module 可以解決以下的問題
- 依賴對象是 abstract class
- 依賴對象是第三方Class,無法添加
@Inject
- 此範例是用 Module 管理 Wheel 的相依性, Car 維持原樣
// 我們要相依的對象是 abstract class
public abstract class Wheel3 {
public abstract String getBrand();
}
/*****************************/
// 實作 wheel 的 class 範例
public class Goodyear extends Wheel3 {
@Override
public String getBrand() {
return "Goodyear";
}
}
會直接定義該 Mudule 所使用的 instance
@Module
public class Wheel3Module {
@Provides
Wheel3 provideWheel3() {
// 在這裡確切的定義 instance
return new Goodyear();
}
}
public class Car3 {
private Wheel3 wheel3;
@Inject
public Car3(Wheel3 wheel3) {
this.wheel3 = wheel3;
}
public String getWheelInfo(){
return "Brand: " + wheel3.getBrand();
}
}
Component
// 要指定使用哪個 modules
@Component(modules = Wheel3Module.class)
public interface ModuleDaggerActivityComponent {
void inject(ModuleDaggerActivity activity);
}
Activity 啟用
public class ModuleDaggerActivity extends AppCompatActivity {
@Inject
Car3 car3;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
DaggerModuleDaggerActivityComponent.create().inject(this);
}
}
- 如果有相依的 abstract class 有數個子類,可以用 Qualifier 進行管理
- 同時,將 Car 也交由 Module 進行管理
public abstract class Wheel4 {
public abstract String getBrand();
}
/* 第一個 child class */
public class Michelin extends Wheel4 {
@Override
public String getBrand() {
return "Michelin";
}
}
/* 第二個 child class */
public class Maxxis extends Wheel4{
@Override
public String getBrand() {
return "Maxxis";
}
}
針對不同的子類設定 method,讓相依對象自行決定要使用哪個子類
@Module
public class Wheel4Module {
@Provides
@MaxxisWheel
Wheel4 provideMaxxis() {
return new Maxxis();
}
@Provides
@MichelinWheel
Wheel4 provideMichelin() {
return new Michelin();
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface MaxxisWheel {}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface MichelinWheel {}
}
public class Car4 {
private Wheel4 wheel4;
public Car4(Wheel4 wheel4) {
this.wheel4 = wheel4;
}
public String getWheelInfo(){
return "Brand: " + wheel4.getBrand();
}
}
@Module
public class Car4Module {
/* 利用 Annotation 指定 相依的子類 */
@Provides
Car4 provideCar4(@Wheel4Module.MichelinWheel Wheel4 wheel4){
return new Car4(wheel4);
}
}
記得要 include 所有的 module
@Component(modules = {Wheel4Module.class, Car4Module.class})
public interface QualifierDaggerActivityComponent {
void inject(QualifierDaggerActivity activity);
}
@Inject
Car4 car4;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
DaggerQualifierDaggerActivityComponent.create().inject(this);
}
將每個 Module 包成 Component,直接使用 Component 之間的 dependencies。其優點是
- 可以獨立使用各個 Component,也可以建立相依
- 可以明確的顯示相依性
Wheel & Car class 基本上沒有變動,以下就不重複寫
@Module
public class Wheel5Module {
@Provides
@DunlopWheel
public Wheel5 provideDunlop() {
return new Dunlop();
}
@Provides
@PirelliWheel
public Wheel5 providePirelli() {
return new Pirelli();
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface DunlopWheel {}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface PirelliWheel {}
}
記得要定義此 component 是管理哪個 Module
@Component(modules = Wheel5Module.class)
public interface Wheel5Component {
@Wheel5Module.DunlopWheel
Wheel5 getDunlopWheel();
@Wheel5Module.PirelliWheel
Wheel5 getPirelliWheel();
}
@Module
public class Car5Module {
/* 用 Annotation 指定相依的子類 */
@Provides
public Car5 provideCar5(@Wheel5Module.PirelliWheel Wheel5 wheel5) {
return new Car5(wheel5);
}
}
可從 Annotaion 看出此 Component 對 WheelComponent 相依
@Component(modules = Car5Module.class, dependencies = Wheel5Component.class)
public interface Car5Component {
Car5 getCar5();
}
可從 Annotaion 看出此 Component 對 CarComponent 相依
@Component(dependencies = Car5Component.class)
public interface ComponentDaggerActivityComponent {
void inject(ComponentDaggerActivity activity);
}
Activity 會寫的複雜一點,可以觀察到是一層層的建立 Component 物件,並且放入相依的對象裡
@Inject
Car5 car5;
@Override
protected void onCreate(Bundle savedInstanceState) {
DaggerComponentDaggerActivityComponent.builder().car5Component(
DaggerCar5Component.builder().wheel5Component(
DaggerWheel5Component.create()
).build()
).build().inject(this);
}
不使用獨立的 Component,而是使用 Subcomponent,適合的情境是:
- Component 之間的相依性非常密切
- Subcomponent 不會單獨使用,而是作為 Component 的延伸
這裡比較特別的是 感覺是由下而上設定其相依關係
跟上一個實作的差別,主要在 Component 的設定(Module 就不重複寫了)
@Component(modules = Wheel6Module.class)
public interface Wheel6Component {
// 需要傳入 car module
Car6Component plus(Car6Module car6Module);
}
使用 Subcomponent
Annotation
@Subcomponent(modules = Car6Module.class)
public interface Car6Component {
SubcomponentDaggerActivityComponent plus();
}
使用 Subcomponent
Annotation
@Subcomponent
public interface SubcomponentDaggerActivityComponent {
void inject(SubcomponentDaggerActivity activity);
}
public class SubcomponentDaggerActivity extends AppCompatActivity {
@Inject
Car6 car6;
@Override
protected void onCreate(Bundle savedInstanceState) {
DaggerWheel6Component.create()
.plus(new Car6Module()) // 這裡居然自己要 new CarModule!
.plus()
.inject(this);
}
}
相依物件可以重複 new instance,所以如果要製作 Singleton instance,需要特別處理
- 這裡是以 Component 的方式建立相依性
- data class & module 省略
通常在 Android Develop 時,會將 Singleton 的設定放在 Application 裡,這裡也採用類似的作法 會在 Application 裡面建立 相依對象的 Component 各個 Activity 會從 Application 拿到該 Component instance
@Component(modules = Wheel7Module.class)
public interface Wheel7Component {
@Wheel7Module.YokohamaWheel
Wheel7 getYokohamaWheel();
}
使用了 @Singleton
@Singleton
@Component(modules = Car7Module.class, dependencies = Wheel7Component.class)
public interface Car7Component {
Car7 getCar7();
}
public class App extends Application {
// Singleton Component Instance
private Car7Component car7Component;
@Override
public void onCreate() {
super.onCreate();
car7Component = DaggerCar7Component.builder().wheel7Component(
DaggerWheel7Component.create()
).build();
}
public Car7Component getCar7Component() {
return car7Component;
}
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ApplicationScope {}
}
這裡不能用 @Singleton
,因為 Dagger 規定 @Singleton 不對相依另一個 @Singleton
所以用了自己定義的 Annotation (定義在 Application 裡)
@App.ApplicationScope
@Component(dependencies = Car7Component.class)
public interface SingletonDaggerActivityComponent {
void inject(SingletonDaggerActivity activity);
}
public class SingletonDaggerActivity extends AppCompatActivity {
@Inject
Car7 car7_1;
@Inject
Car7 car7_2;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// 直接使用 Applicaiont 的 Component Instance
DaggerSingletonDaggerActivityComponent.builder()
.car7Component(
((App)getApplication()).getCar7Component()
)
.build().inject(this);
Log.d("crazyma","car7_1 : " + car7_1);
Log.d("crazyma","car7_2 : " + car7_2);
}
}