簡單總結一下 方便日後查詢
Dagger2是爲了解決對象依賴關係而生的依賴注入框架 目的是爲了降低代碼耦合 它會在編譯後自動爲被inject的類添加所需要new出對應對象的代碼
用大白話說
就比如
@Inject
User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_c);
DaggerCActivityComponent.builder().cUserModule(new CUserModule()).build().inject(this);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(user.toString());
}
這裏先@inject User user 看到這個 意味着我們下面的代碼 等會如果哪裏要用到這個user 實例了 就不需要重新new了 Dagger2會在編譯的時候自動幫我們new出來
在項目中引入Dagger2需要修改兩個地方的gradle文件,首先是project的gradle文件,修改成如下樣子:
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
然後修改module的gradle文件:
apply plugin: 'com.neenbedankt.android-apt'
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.1.1'
compile 'com.google.dagger:dagger:2.6'
apt 'com.google.dagger:dagger-compiler:2.6'
compile 'com.squareup.picasso:picasso:2.5.2'
}
這裏有幾個地方需要說一下,首先Dagger2我們可以直接在jCenter中搜索到的,可以搜到之後直接添加,那麼和Dagger2有關的是兩個文件:
compile 'com.google.dagger:dagger:2.6'
apt 'com.google.dagger:dagger-compiler:2.6'
但是這兩個一個用了compile一個用了apt,使用apt表示該引用類庫只在編譯的時候起作用,在打包的時候並不會打包到apk中去。
@Module
public class UserModule {
@Provides
@Singleton
User providesUser() {
return new User();
}
}
povidesUser() 方法返回了一個User對象
就在Module裏被@Provides修飾的方法裏定義
這裏providersUser()方法剛好返回的是User對象 方法體很簡單就是new User();
所以當Activity在用到User對象的時候,它就知道,我需要去Module裏找對應的生成方法了,找到對應的Module 後,再在Module裏找被@Provides修飾的方法,這個方法就爲Dragger2提供了構建新對象的具體方法
4@Component
看到了@Module和@provides之後 還有一個疑問 就是 我知道被inject之後 一旦需要用到它的實體 我會到modules裏面找 但Dagger2裏 modules並不止一個
事實上 Dagger2允許你自定義無窮多的Modules 只要一個類裏 有provides方法 然後被@Modules修飾 它就算是一個Module 。
那麼多的Modules 如何告訴Dagger去那個裏面找 這就需要用到一個新的註解 叫做@Component
一個Component 就類似一個注射器 他把藥物 Modules 和 病人 (使用了依賴對象的類 比如這裏片頭的Activity )聯繫在了一起
他的定義方式很簡單@Singleton
@Component(modules = UserModule.class)
public interface ActivityComponent {
void inject(MainActivity activity);
}
先用@Component註解修飾 告訴Dragger2這是一個組件(注射器),後面(modules=xxxModule.class , yyyModule.class...)告訴這個注射器可以打哪幾種藥物,組件都是接口,接口中定義了inject方法,這裏的inject方法中需要傳入一個病人對象,比如這裏傳入的是MainActivity ,這樣一來,一個注射器就定義好了,他把Modules和注入的對象聯繫在一起了,這裏可以定義多個帶有不同參數的jnject方法 比如
@UserScope
@Component(modules = UserModule.class)
public interface ActivityComponent {
void inject(MainActivity activity);
void inject(BActivity activity);
}
這涉及到下面要說的 @scope註解了
5@scope
顧名思義 他是用來定義作用域的
前面用的@singleton 是系統自帶的一個scope 被它修飾的類它意味着在整個項目中只有一個實體 ,也就是全局單利 模式,在實際開發過程中,除了全局單例,更常見的是局部單例,比如
以下參考博主
http://blog.csdn.net/u012702547/article/details/52213706
我們有三個Activity,MainActivity,BActivity和CActivity,我們想讓MainActivity和BActivity共享同一個實例,而讓CActivity獲取另外一個實例,這又該怎麼實現呢?在Dagger2中,我們可以通過自定義Scope來實現局部單例。
首先讓我們先來定義一個局部作用域:@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface UserScope {
}
然後在我們的UserModule和ActivityComponent中應用該局部作用域:
@Module
public class UserModule {
@Provides
@UserScope
User providesUser() {
return new User();
}
}
@UserScope
@Component(modules = UserModule.class)
public interface ActivityComponent {
void inject(MainActivity activity);
void inject(BActivity activity);
}
請大家注意,我的ActivityComponent作爲一個注入器只可以向MainActivity和BActivity兩個Activity中注入依賴,不可以向CActivity中注入依賴。最後,要讓該局部作用域產生單例效果,需要我們在自定義的Appliation類中來初始化這個Component,如下:
public class MyApp extends Application {
ActivityComponent activityComponent;
@Override
public void onCreate() {
super.onCreate();
activityComponent = DaggerActivityComponent.builder().userModule(new UserModule()).build();
}
ActivityComponent getActivityComponent(){
return activityComponent;
}
}
接下來我們在MainActivity和BActivity中注入依賴,MainActivity如下:
@Inject
User user;
@Inject
User user2;
private TextView tv;
private TextView tv2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// DaggerActivityComponent.builder().userModule(new UserModule()).build().inject(this);
((MyApp) getApplication()).getActivityComponent().inject(this);
tv = ((TextView) findViewById(R.id.tv));
tv2 = ((TextView) findViewById(R.id.tv2));
tv.setText(user.toString());
tv2.setText(user2.toString());
}
BActivity如下:
@Inject
User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
((MyApp) getApplication()).getActivityComponent().inject(this);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(user.toString());
}
那麼如果我還想在CActivity中使用User對象該怎麼辦呢?再來一個CUserModule和CActivityComponent
CUserModule如下:
@Module
public class CUserModule {
@Provides
User providesUser() {
return new User();
}
}
這裏沒有再著名單例
CActivityComponent如下:
@Component(modules = CUserModule.class)
public interface CActivityComponent {
void inject(CActivity activity);
}
在CActivity中注入依賴:
@Inject
User user;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_c);
DaggerCActivityComponent.builder().cUserModule(new CUserModule()).build().inject(this);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(user.toString());
}
運行結果如下:
可以看到,MainActivity和BActivity是同一個實例,而CActivity則是另外一個實例。
@UserScope在這裏到底起了什麼作用?我引用網上一段話:
以下文字來源:http://blog.csdn.net/u012943767/article/details/51941872
Scope的使用,如何實現單例?
這個迷之Scope也是有點難以理解,我們在哪裏使用到了Scope呢。在我們的AppComponent中添加了一個註解爲@Singleton,@Singleton就是一個Scope,據說可以實現單例喲。。。難道這樣就實現了單例模式?我剛剛開始是這樣理解的。直到仔細的看了幾遍這篇文章我才知道並不是這樣的。
事實上@Sinleton中並沒有創建單例的能力,那麼AppComponent中提供的依賴注入是如何實現單例的呢。其實這個原理很賤單。
首先Module提供了創建實例的方法,接着AppComponent中對Module進行管理,最後AppComponent在自定義Applicaiton中被實例化了一次。
這個實例化了一次是最重要的呀。僅僅被實例化了一次,那不就是單例麼。就是這麼簡單呀。
可能有些童靴當時就不樂意了,那既然這樣都已經實現了單例,那麼這個@Singltop還要來何用?不是多此一舉嗎。
其實@Singletop還有有一些作用的,首先一方面能讓你直面的瞭解到這是一個單例,其次這個@Singletop能夠更好的管理Modlue和Component之間的關係。
Dagger2需要保證Component和Module是匹配的,就需要用到這個註解。