Dagger2是一個(gè)Android依賴(lài)注入框架,由Google Fork 的 Square公司的Dagger基礎(chǔ)上再開(kāi)發(fā)琴儿。傳統(tǒng)的MVC框架Activity比較臃腫孕索,難以維護(hù),現(xiàn)在主流的架構(gòu)還是使用MVP(Mode + View + Presenter)的方式赛惩。但是MVP框架也有可能在Presenter中集中大量代碼哀墓,引入Dagger2可以實(shí)現(xiàn)Presenter與Activity直接的解耦,提高模塊化和可維護(hù)性喷兼。Jake Wharton 在對(duì) Dagger 的介紹中指出篮绰,Dagger 即 DAG-er,這里的 DAG 即數(shù)據(jù)結(jié)構(gòu)中的 DAG——有向無(wú)環(huán)圖(Directed Acyclic Graph)季惯。也就是說(shuō)吠各,Dagger 是一個(gè)基于有向無(wú)環(huán)圖結(jié)構(gòu)的依賴(lài)注入庫(kù),因此Dagger的使用過(guò)程中不能出現(xiàn)循環(huán)依賴(lài)勉抓。
Dagger2
基本特點(diǎn)(反射機(jī)制):
- 沒(méi)有反射贾漏,在編譯時(shí)執(zhí)行(圖的驗(yàn)證、配置和預(yù)先設(shè)置)
- 容易調(diào)試和可跟蹤(具體的調(diào)用和創(chuàng)建堆棧)
- 代碼混淆(使用派遣方法)
Dagger2通過(guò)注解來(lái)生成代碼藕筋,定義不同角色纵散,主要的注解有:@Inject、@Module隐圾、@Componet伍掀、@Provides、@Scope暇藏、@SubComponet等
? @Inject: 通常在需要依賴(lài)的地方使用這個(gè)注解蜜笤。換句話(huà)說(shuō),你用它告訴Dagger這個(gè)類(lèi)或者字段需要依賴(lài)注入盐碱。這樣瘩例,Dagger就會(huì)構(gòu)造一個(gè)這個(gè)類(lèi)的實(shí)例并滿(mǎn)足他們的依賴(lài)。
? @Module: Modules類(lèi)里面的方法專(zhuān)門(mén)提供依賴(lài)甸各,所以我們定義一個(gè)類(lèi)垛贤,用@Module注解,這樣Dagger在構(gòu)造類(lèi)的實(shí)例的時(shí)候趣倾,就知道從哪里去找到需要的 依賴(lài)聘惦。modules的一個(gè)重要特征是它們?cè)O(shè)計(jì)為分區(qū)并組合在一起(比如說(shuō),在我們的app中可以有多個(gè)組成在一起的modules)。
? @Provides: 在modules中善绎,我們定義的方法是用這個(gè)注解黔漂,以此來(lái)告訴Dagger我們想要構(gòu)造對(duì)象并提供這些依賴(lài)。
? @Component: Components從根本上來(lái)說(shuō)就是一個(gè)注入器禀酱,也可以說(shuō)是@Inject和@Module的橋梁炬守,它的主要作用就是連接這兩個(gè)部分。 Components可以提供所有定義了的類(lèi)型的實(shí)例剂跟,比如:我們必須用@Component注解一個(gè)接口然后列出所有的 @Modules組成該組件减途,如 果缺失了任何一塊都會(huì)在編譯的時(shí)候報(bào)錯(cuò)。所有的組件都可以通過(guò)它的modules知道依賴(lài)的范圍曹洽。
@Scope: Scopes可是非常的有用鳍置,Dagger2可以通過(guò)自定義注解限定注解作用域。這是一個(gè)非常強(qiáng)大的特點(diǎn)送淆,因?yàn)闆](méi)必要讓每個(gè)對(duì)象都去了解如何管理他們的實(shí)例税产。
? Qualifier: 當(dāng)類(lèi)的類(lèi)型不足以鑒別一個(gè)依賴(lài)的時(shí)候,我們就可以使用這個(gè)注解標(biāo)示偷崩。例如:在Android中辟拷,我們會(huì)需要不同類(lèi)型的context,所以我們就可以定義 qualifier注解“@ForApplication”和“@ForActivity”阐斜,這樣當(dāng)注入一個(gè)context的時(shí)候衫冻,我們就可以告訴 Dagger我們想要哪種類(lèi)型的context。
上代碼
bulid.gradle(Project)
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.1'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
build.gradle(Module)
compile 'com.google.dagger:dagger:2.0.2'
compile 'com.google.dagger:dagger-compiler:2.0.2'
provided 'org.glassfish:javax.annotation:10.0-b28'
項(xiàng)目結(jié)構(gòu)圖
?本項(xiàng)目提供兩個(gè)例子智听,分別是兩種不同的框架注入模式 具體代碼后面給鏈接
-
第一種方式
對(duì)于不同的Activity羽杰,創(chuàng)建各個(gè)對(duì)應(yīng)的ActivityCompontent,同時(shí)把Presenter(Biz)注入到Component的視圖中到推,這也是dagger2推薦的做法考赛,Dagger 2希望使用@Component注解接口將依賴(lài)關(guān)系鏈接起來(lái)。
di包下面是一些跟隨Application生命周期的依賴(lài)方法與實(shí)例莉测,其中AppModule與AppServiceModule提供了全局的Context與User類(lèi)颜骤,UI包下面就是具體的MVP的代碼
Appmodule.java
@Module
public class AppModule {
private final App application;
public AppModule(App application) {
this.application = application;
}
@Provides
@Singleton
App provideApplicationContext() {
return application;
}
}
AppServiceModule.java
@Module
public class AppServiceModule {
@Provides
User provideUser() {
User user = new User();
user.setId("1");
user.setName("hello world");
return user;
}
}
Modules類(lèi)里面的方法專(zhuān)門(mén)提供依賴(lài)
?
UI下面的代碼
@ActivityScope
@Component(modules = LoginAcivityModule.class, dependencies = AppComponent.class)
public interface LoginActivityComponent {
LoginActivity inject(LoginActivity mainActivity);
LoginActivityPresenter presenter();
}
@Module
public class LoginAcivityModule {
private LoginActivity mLoginActivity;
public LoginAcivityModule(LoginActivity loginActivity) {
this.mLoginActivity = loginActivity;
}
@Provides
@ActivityScope
LoginActivity provideMainActivity() {
return mLoginActivity;
}
@Provides
@ActivityScope
LoginActivityPresenter provideMainActivityPresenter(LoginActivity loginActivity, User user) {
return new LoginActivityPresenter(loginActivity, user);
}
}
public class LoginActivityPresenter {
private LoginActivity mainActivity;
private User user;
public LoginActivityPresenter(LoginActivity mainActivity, User user) {
this.mainActivity = mainActivity;
this.user = user;
}
public void showUserName() {
System.out.println(user.getName());
mainActivity.setUserName(user.getName());
}
}
到這注入初步就可以了。
使用:
public class LoginActivity extends BaseActivity {
private TextView mytext;
@Inject
LoginActivityPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mytext = (TextView) findViewById(R.id.mytext);
presenter.showUserName();
}
@Override
protected void setupActivityComponent(AppComponent appComponent) {
DaggerLoginActivityComponent.builder()
.appComponent(appComponent)
.loginAcivityModule(new LoginAcivityModule(this))
.build()
.inject(this);
}
public void setUserName(String userName){
mytext.setText(userName);
}
}
Dagger生成的代碼
這里只介紹LoginActivity捣卤,AppComponent生成是一樣的忍抽。
DaggerLoginActivityComponent.build會(huì)創(chuàng)建LoginActivity_MembersInjector,LoginActivity_MembersInjector會(huì)為L(zhǎng)oginActivity的所有注入成員提供依賴(lài)董朝,只要調(diào)用inject()鸠项,就能獲取所需的字段和依賴(lài)。
在引用inject的時(shí)候子姜,Dagger會(huì)為我們生成祟绊,上面的例子則會(huì)生成LoginAcivityModule_ProvideMainActivityPresenterFactory的工廠(chǎng),這個(gè)工廠(chǎng)實(shí)現(xiàn)就是創(chuàng)建了LoginActivityPresenter的實(shí)例。
- DaggerLoginActivityComponent類(lèi)牧抽,我們有一個(gè)Provider嘉熊,它不僅僅是一個(gè)提供實(shí)例的接口,它還是被ScopedProvider構(gòu)造出來(lái)的扬舒,可以記錄創(chuàng)建實(shí)例的范圍阐肤。
end
到此Dagger2的簡(jiǎn)單使用就差不多了,另外還有一種MVP方式結(jié)合的Dagger2例子讲坎,第二個(gè)例子是沒(méi)有將Presenter是注入到Component中的,好處就是節(jié)省了代碼孕惜。下面給出例子源碼鏈接