有什麼能比那把黃油刀(butterknife)更加犀利的名字惟有dagger了html
最先的版本Dagger1 由Square公司開發。依賴注入框架主要用於模塊間解耦,提升代碼的健壯性和可維護性。Dagger 這個庫的取名不只僅來自它的本意「匕首」同時也暗示了它的原理java
Dagger2 是一個Android依賴注入框架,由谷歌開發,由於主流是Dagger2因此接下來咱們直接學習如何使用它android
說了那麼多,那到底依賴注入是什麼呢?上代碼:git
public class MainActivity extends AppCompatActivity {
User user;
public void setUser(User user) {
this.user = user;
}複製代碼
依賴:MainActivity 包含了一個User對象,咱們就說MainActivity 依賴於user;
注入:由於user對象是經過傳遞初始的,不是直接new出的對象,因此這樣的方式就叫作注入;
經過上面簡單的一小段代碼估計你們對依賴注入有了瞭解,經過依賴注入能夠有效的減小咱們的耦合,既然這樣能夠實現依賴注入,爲何還須要dagger這樣的第三方庫處理呢?github
首先new一個實例的過程是一個重複的簡單體力勞動,dagger2徹底能夠把new一個實例的工做作了,所以咱們把主要精力集中在關鍵業務上、同時也能增長開發效率上。
省去寫單例的方法,而且也不須要擔憂本身寫的單例方法是否線程安全,本身寫的單例是懶漢模式仍是餓漢模式。由於dagger2均可以把這些工做作了。設計模式
每一個app中的ApplicationComponent管理整個app的全局類實例,全部的全局類實例都統一交給ApplicationComponent管理,而且它們的生命週期與app的生命週期同樣。
每一個頁面對應本身的Component,頁面Component管理着本身頁面所依賴的全部類實例。
由於Component,Module,整個app的類實例結構變的很清晰。安全
假如不用dagger2的話,一個類的new代碼是很是可能充斥在app的多個類中的,假如該類的構造函數發生變化,那這些涉及到的類都得進行修改。設計模式中提倡把容易變化的部分封裝起來。app
說了那麼多概念,估計你們已經對dagger有了必定的瞭解,那開我們的使用吧,畢竟實戰纔是最有用的嘛框架
仍是結合一開始的例子,咱們採用dagger的方式看如何給MainActivity 傳遞一個依賴的user對象maven
// Add plugin https://bitbucket.org/hvisser/android-apt
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
// Apply plugin
apply plugin: 'com.neenbedankt.android-apt'
// Add Dagger dependencies
dependencies {
compile 'com.google.dagger:dagger:2.x'
apt 'com.google.dagger:dagger-compiler:2.x'
}複製代碼
@Inject: 一般在須要依賴的地方使用這個註解。換句話說,你用它告訴Dagger這個類或者字段須要依賴注入。這樣,Dagger就會構造一個這個類的實例並知足他們的依賴。
@Module: Modules類裏面的方法專門提供依賴,因此咱們定義一個類,用 @Module註解,這樣Dagger在構造類的實例的時候,就知道從哪裏去找到須要的 依賴。modules的一個重要特徵是它們設計爲分區並組合在一塊兒(好比說,在咱們的app中能夠有多個組成在一塊兒的modules)。
@Provides: 在modules中,咱們定義的方法是用這個註解,以此來告訴Dagger咱們想要構造對象並提供這些依賴。
@Component: Components從根本上來講就是一個注入器,也能夠說是@Inject和@Module的橋樑,它的主要做用就是鏈接這兩個部分。 Components能夠提供全部定義了的類型的實例,好比:咱們必須用@Component註解一個接口而後列出全部的 @Modules組成該組件,如 果缺失了任何一塊都會在編譯的時候報錯。全部的組件均可以經過它的modules知道依賴的範圍。
@Scope: Scopes但是很是的有用,Dagger2能夠經過自定義註解限定註解做用域。後面會演示一個例子,這是一個很是強大的特色,由於就如前面說的同樣,不必讓每一個對象都去了解如何管理他們的實例
能夠粗濾的過一遍,估計看完也是一頭霧水,仍是投入到實戰中去認識吧!
和傳統方法同樣很少講了,設置一些屬性罷了
public class User {
private String name;
private String sex;
private String ads;
******get/set**********
}複製代碼
module類就是給user初始化而且提供外部調用的類,這裏類中咱們須要給user初始,而且返回給dagger一個可調用的對象
@Module
public class UserModule {
@Provides
User provideUser(){
return new User("xxxx","SEX","XXX@Gmail.com");
}
}複製代碼
使用@Module標識類型爲module,並用@Provides標識提供依賴的方法
有了提供依賴的組件(module),咱們還須要將依賴注入到須要的對象中。鏈接提供依賴和消費依賴對象的組件被稱爲Injector。Dagger2中咱們將這個對象其稱爲component。UserComponent代碼以下
@Component(modules = UserModule.class)
public interface UserComponent {
void inject(MainActivity mainActivity);
}複製代碼
能夠看到,Component是一個使用@Component標識的Java interface。interface的inject方法須要一個消耗依賴的類型對象做爲參數:經過 @Component 添加了一個 Module : UserModule,此外還有一個inject方法,其中的參數表示要注入的位置(先打個預防針,Component中的方法還能夠起到暴露資源,實現Component中的「繼承」的做用)
注意:這裏必須是真正消耗依賴的類型MainActivity,而不能夠寫成其父類,好比Activity。由於Dagger2在編譯時生成依賴注入的代碼,會到inject方法的參數類型中尋找能夠注入的對象,可是實際上這些對象存在於MainActivity,而不是Activity中。若是函數聲明參數爲Activity,Dagger2會認爲沒有須要注入的對象。當真正在MainActivity中建立Component實例進行注入時,會直接執行按照Activity做爲參數生成的inject方法,致使全部注入都失敗。(是的,我是掉進這個坑了。)
最後,咱們須要在MainActivity中構建Injector對象,經過dagger獲得咱們的user對象
public class MainActivity extends AppCompatActivity {
@Inject
User user;
UserComponent component;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
component= DaggerUserComponent.builder().userModule(new UserModule()).build();
component.inject(this);
TextView textView=(TextView)findViewById(R.id.tv);
textView.setText("name:"+user.getName()+"\nsex:"+user.getSex()+"\nads:"+user.getAds());
}
}複製代碼
首先,使用@Inject標誌被注入的對象User (注意User 不能爲private),以後經過Dagger2生成的實現了咱們提供的UserComponent 接口類DaggerUserComponent建立component,調用其inject方法完成注入。
至此,咱們使用Dagger實現了最簡單的依賴注入!
注意:這裏的DaggerUserComponent不是咱們本身建立的,是dagger自動在build時(可手動make project)建立的,後邊的userModule也是更具你在Component設置的module對象生成的方法-若是不成功需先clean工程在make一遍