本片文章將介紹Dagger2的作用及使用方式职车。
什么是Dagger2渴庆?
- Dagger2是在編譯時期生成代碼實現(xiàn)完整依賴注入的框架
Dagger 2 is a compile-time evolution approach to dependency injection. Taking the approach started in Dagger 1.x to its ultimate conclusion, Dagger 2.x eliminates all reflection, and improves code clarity by removing the traditional ObjectGraph/Injector in favor of user-specified @Component interfaces.
什么是依賴注入家妆?
- 依賴注入作用
-
是實現(xiàn)控制反轉(zhuǎn)(Inversion of Control)的最常見的方式之一
控制反轉(zhuǎn) 是一種面向?qū)ο缶幊讨械囊环N設計原則对省,用來減低計算機代碼之間的耦合度炬藤。其基本思想是:借助于“第三方”實現(xiàn)具有依賴關系的對象之間的解耦。
簡單說就是如果對象A依賴于對象B饺窿,那么對象A自己需要主動去創(chuàng)建對象B歧焦,無論是創(chuàng)建還是使用對象B,控制權都在自己手上肚医。而控制反轉(zhuǎn)的思想是對象A與對象B之間失去直接聯(lián)系绢馍,當對象A需要對象B的時候,IOC容器會主動創(chuàng)建一個對象B注入到對象A需要的地方肠套。
-
目的在于解耦
- 常見耦合場景:一個類中直接創(chuàng)建另一個類的對象的代碼舰涌,這樣的操作和硬編碼一樣,會導致耦合你稚,我們把這種初始化方式稱為硬初始化(hard init)瓷耙。
- 硬初始化的壞處:
- 修改構(gòu)造函數(shù)實現(xiàn)時朱躺,需要修改創(chuàng)建處的代碼
- 不便于測試,直接創(chuàng)建另一個類對象的類無法單獨被測試搁痛,其行為和另一個類緊緊耦合在一起长搀,同時,也會導致代碼的可讀性問題鸡典。
-
- 依賴注入常見3種方式:
- 構(gòu)造函數(shù)注入
public class MovieLister { private MovieFinder finder; public MovieLister(MovieFinder finder) { this.finder = finder; } ... }
- setter注入
public class MovieLister { ... public void setFinder(MovieFinder finder) { this.finder = finder; } }
- 接口注入
public interface InjectFinder { void injectFinder(MovieFinder finder); } class MovieLister implements InjectFinder { ... public void injectFinder(MovieFinder finder) { this.finder = finder; } ... }
- 構(gòu)造函數(shù)注入
使用Dragger2進行依賴注入
- 常見的硬初始化代碼
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
UserModel user = new UserModel();
((TextView) findViewById(R.id.user_desc_line)).setText(user.id + "\n" + user.name + "\n" + user.gender);
}
...
}
一但UserModel的構(gòu)造發(fā)生改變那么我們要修改所有實例化UserModel的代碼骏全。
- 使用Dagger2實現(xiàn)方式
- 目標:對于依賴類的修改不影響使用該類實例的類代碼
- 步驟:
-
構(gòu)建依賴
- 將創(chuàng)建對象的代碼隔離起來顾瞪,保證使用的類不受其后期更改影響
- 負責提供依賴的組件被稱為Module
@Module public class ActivityModule { @Provides UserModel provideUserModel() { return new UserModel(); } }
- 使用@Module標識該類為Module野蝇,并用@Provides標識提供依賴的方法晰赞。
-
構(gòu)建Injector
- 將依賴注入到需要的對象中
- 連接提供依賴和消費依賴對象的組件被稱為Injector。Dagger2中疗垛,我們將其稱為component症汹。
@Component(modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity activity); }
- Component是一個使用@Component標識的Java 接口。接口的inject方法入?yún)樾枰撘蕾嚨念愋汀?/li>
- 注意:這里必須是真正消耗依賴的類型MainActivity贷腕,而不可以寫成其父類背镇,比如Activity。因為Dagger2在編譯時生成依賴注入的代碼泽裳,會到inject方法的參數(shù)類型中尋找可以注入的對象瞒斩,但是實際上這些對象存在于MainActivity,而不是Activity中涮总。所以如果函數(shù)聲明參數(shù)為Activity胸囱,Dagger2在Activity中找不到要注入的對象,導致所有注入都失敗瀑梗。
-
完成依賴注入:在需要依賴的地方創(chuàng)建Injector烹笔,完成注入
public class MainActivity extends ActionBarActivity { private ActivityComponent mActivityComponent; @Inject UserModel userModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mActivityComponent = DaggerActivityComponent.builder().activityModule(new ActivityModule()).build(); mActivityComponent.inject(this); ((TextView) findViewById(R.id.user_desc_line)).setText(userModel.id + "\n" + userModel.name + "\n" + userModel.gender); } ... }
- 使用@Inject標志被注入的對象userModel(注意userModel不能為private)
- 通過Dagger2生成的實現(xiàn)ActivityComponent接口類DaggerActivityComponent創(chuàng)建component,調(diào)用其inject方法完成注入抛丽。
-
Dagger2通過將創(chuàng)建依賴類對象的代碼獨立起來谤职,保證使用的類不受依賴類的構(gòu)造改變而受到影響,同時通過注解在編譯時動態(tài)生成代碼注入到被依賴類中亿鲜,實現(xiàn)依賴類和被依賴類解耦允蜈。
參考文獻: