在講Dagger2之前呢,我先列一個(gè)事例代碼,看看用了Dagger2之后有什么不一樣的地方。
public class A {
private B b;
private C c;
public A() {
b = new B();
c = new C();
}
}
public class B {
}
public class C {
}
該事例代碼在A中引用了B和C,這個(gè)沒什么,那如果當(dāng)B和C業(yè)務(wù)復(fù)雜了呢,需要增加屬性:
public class B {
private String name;
public B(String name) {
this.name = name;
}
}
public class C {
private int age;
public C(int age) {
this.age = age;
}
}
那是不是A里面的代碼也跟著發(fā)生變化了呢,是的,傳參變了,那調(diào)用方肯定也發(fā)生變化了。所以說這種業(yè)務(wù)邏輯的改變是說不準(zhǔn)的。下面看看Dagger2是怎么寫這種變動(dòng)的邏輯:
public class B {
@Inject
public String name;
@Inject
public B() {
}
}
public class C {
@Inject
public int age;
@Inject
public C() {
}
}
public class A {
@Inject
public B b;
@Inject
public C c;
@Inject
public A() {
// b = new B("張三");
// c = new C(12);
}
}
上面改動(dòng)的代碼中,A中依賴了B和C,B和C中的構(gòu)造方法提供了@Inject注解來說明自己是被Dagger2來生成,同樣A中也說明了依賴的B和C是被Dagger2來管理起來了。注意上面如果需要用到@Inject注解,屬性是不能用private來修飾的。僅有上面的代碼,是沒法動(dòng)態(tài)生成A的,此時(shí)需要借助@Component注解和@Module注解:
@Component(modules = AbcMondel.class)
public interface Abc {
A getA();
}
@Module
public class AbcMondel {
@Provides
public String provideName() {
return "張三";
}
@Provides
public int provideAge() {
return 10;
}
}
其實(shí)這里可以看做是Component注解是主要組合@Module注解的,而@Module就是專門提供模型和數(shù)據(jù)的。當(dāng)初始化B和C的時(shí)候,發(fā)現(xiàn)Module中有提供參數(shù)age和name,因此直接使用該處的內(nèi)容。在調(diào)用方直接去生成A:

其實(shí)對(duì)于這種生成數(shù)據(jù)肯定在實(shí)際業(yè)務(wù)邏輯中不行,比如說我們的數(shù)據(jù)來自于網(wǎng)絡(luò)層,數(shù)據(jù)肯定得從activity中傳過來的呀,那此時(shí)怎么去傳這個(gè)值呢:
@Module
public class AbcMondel {
private String name;
private int age;
public AbcMondel(String name, int age) {
this.name = name;
this.age = age;
}
@Provides
public String provideName() {
return name;
}
@Provides
public int provideAge() {
return age;
}
}
這里主要改動(dòng)的地方AbcMondel,通過構(gòu)造器將參數(shù)傳進(jìn)來。那調(diào)用的地方是啥樣的:

上面多了一個(gè)abcMondel方法,該方法就是根據(jù)Module來生成的。
其實(shí)上面的B和C對(duì)象也可以直接放在model中通過Provides來生成,具體怎么玩看如下代碼:
public class B {
public String name;
public B(String name) {
this.name = name;
}
//無參的注入構(gòu)造器,為了驗(yàn)證dagger2是以inject注入為主,還是 以Provides注解的注入方式為主
@Inject
public B() {
this.name = "李四";
}
}
public class C {
public int age;
@Inject
public C() {
}
public C(int age) {
this.age = age;
}
}
public class Cc extends C {
@Inject
public Cc() {
super(100);
}
public Cc(int age) {
this.age = age;
}
}
@Module
public class AbcMondel {
// private String name;
// private int age;
// public AbcMondel(String name, int age) {
// this.name = name;
// this.age = age;
// }
//Provides直接提供的是B的有參構(gòu)造
@Provides
public B provideB() {
return new B("xc");
}
}
@Module
public class AbcMondel {
// private String name;
// private int age;
// public AbcMondel(String name, int age) {
// this.name = name;
// this.age = age;
// }
@Provides
public B provideB() {
return new B("xc");
}
@Provides
public C provideC(Cc c) {
return c;
}
}

看到打印的數(shù)據(jù)沒,name是通過Provides注解傳遞進(jìn)去的,age是通過Cc類里面獲取到的,因此這里可以得到兩個(gè)結(jié)論,如果inject和Provides同時(shí)提供了依賴,那此時(shí)優(yōu)先去看Provides有沒有提供相應(yīng)的依賴,沒有的話才去找inject相應(yīng)的構(gòu)造器;再個(gè)就是看到C提供的依賴沒,他是通過傳參的形式生成依賴的,所以從B和C生成依賴的方式也大概知道什么時(shí)候通過傳參的形式,什么時(shí)候通過new的形式
new的形式呢,是通過手動(dòng)去new,說明該類的構(gòu)造器沒有被依賴,直接通過形參的形式呢,說明該類已經(jīng)在構(gòu)造器上標(biāo)注了@inject注解,因此像我們自己寫的類就通過傳參的形式,因?yàn)樽约簩懙囊话銟?gòu)造器上都有inject注解,像第三方的sdk沒有辦法改動(dòng)源碼,因此只能通過new的形式生成注解
Component通過傳參的形式實(shí)現(xiàn)注入
這里用android中常用的mvp框架來做例子:
首先寫好p層:
public class MainPresenter {
private static final String TAG = MainPresenter.class.getSimpleName();
MainActivityView.Iview mainActivityView;
@Inject
public MainPresenter(MainActivityView.Iview mainActivityView) {
this.mainActivityView = mainActivityView;
}
public void loadPage() {
mainActivityView.loadStart();
Log.d(TAG, "loadPage");
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
mainActivityView.loadEnd();
}
}, 3000);
}
}
p層有MainActivityView.Iview引用,實(shí)際上就是MainActivity的實(shí)例,那此時(shí)肯定要在Module中提供該形參的實(shí)例:
@Module
public class PresenterModel {
private final MainActivityView.Iview mView;
public PresenterModel(MainActivityView.Iview view) {
mView = view;
}
@Provides
MainActivityView.Iview provideMainView() {
return mView;
}
}
前面已經(jīng)說過,如果該類是系統(tǒng)定義的類,那么此時(shí)是可以通過new的方式提供給注入的參數(shù),如果不是系統(tǒng)的可以通過在該類的構(gòu)造器上面加上@inject注解。顯然這個(gè)MainActivityView.Iview是activity實(shí)例,因此需要我們new或者傳參進(jìn)來,很顯然MainActivity實(shí)例是不允許直接new的,因此需要傳參進(jìn)來。
Component部分代碼:
@Component(modules = PresenterModel.class)
public interface PresenterComponent {
void inject(MainActivity mainActivity);
// @Component.Builder
// interface Builder {
// PresenterComponent.Builder view(MainActivityView.Iview view);
//
// PresenterComponent build();
// }
}
activity中的代碼:
DaggerPresenterComponent.builder().presenterModel(new PresenterModel(this)).build().inject(this);
主要就這么一句,相信大家對(duì)mvp簡(jiǎn)單的架子搭建肯定是沒問題了。
對(duì)于該框架大家需要多用,自然就比較順手用了。
Singleton注解
其實(shí)從字面意思就大致明白是什么作用了,下面用一個(gè)事例來說明下該注解的意思:

這個(gè)是A類上加了singleton注解,還有在相應(yīng)的Component接口類也需要加上該注解才能編譯成功:

在MainActivity中可以驗(yàn)證這一注解:

這里改變了b中的name字段,那么可以看下兩個(gè)name的變化:

所以從圖上看也確實(shí)驗(yàn)證了這一結(jié)論。其實(shí)這里的單例是跟Component接口一起走的,因?yàn)镾ingleton注解的單例范圍就是在某一個(gè)Component接口內(nèi)的,跨Component是沒有單例的說法。
說到這里其實(shí)很想知道大部分項(xiàng)目中用到了自定義的屬性,比如說:

這里定義的注解和singleton注解是一樣的,因此可以說明它的作用和singleton是一樣的,為了保證在Component作用域內(nèi)該對(duì)象一直處于單例的狀態(tài)。
更多內(nèi)容點(diǎn)擊
關(guān)于mvp的例子大家可以閱讀這里