系列文章第一篇:
http://www.reibang.com/p/33b739bd721a
概述
上一期我們已經(jīng)對Dagger的基本概念以及結(jié)構(gòu)做了介紹活逆。那么現(xiàn)在我們將對Dagger作深入探究,了解它究竟是怎么實(shí)現(xiàn)自動(dòng)注入的驼侠,它在我們引用注解后做了哪些工作教硫。探究
2.1 思路
在古代涧尿,人們選擇靠近水源的地點(diǎn)作為聚居地百新,很大一部分原因是我們需要水來灌溉莊稼帖蔓。我們可以把步驟大概簡化為:水源(提供水)——水車(獲取水)——導(dǎo)管(引流)——農(nóng)田矮瘟。其實(shí)Dagger注入也是遵循這個(gè)過程,下面我們按照這個(gè)思路對dagger進(jìn)行剖析塑娇。
上篇我們說過澈侠,Module是專門提供依賴的,可以看作水源埋酬;Component是注入器哨啃,我們可以把它看成水車烧栋;Inject是被注入的對象,是農(nóng)田和莊稼拳球。
2.2 Module
在探究Module之前我們首先了解一下Module類的寫法:
@Module
public class ApplicationModule {
private final AndroidApplication mApplication;
private final DaoSession mDaoSession;
private final RxBus mRxBus;
public ApplicationModule(AndroidApplication application, DaoSession daoSession, RxBus rxBus) {
mApplication = application;
mDaoSession = daoSession;
mRxBus = rxBus;
}
@Provides
@Singleton
Context provideApplicationContext() {
return mApplication.getApplication();
}
@Provides
@Singleton
RxBus provideRxBus() {
return mRxBus;
}
@Provides
@Singleton
DaoSession provideDaoSession() {
return mDaoSession;
}
}
@Providers表示此處會(huì)提供依賴审姓,而@Singleton表示提供的依賴對象將是單例形式。
好的祝峻,我們現(xiàn)在已經(jīng)有了依賴提供者魔吐,就相當(dāng)于有了一個(gè)農(nóng)民伯伯為莊稼找到了水源,現(xiàn)在我們需要想辦法將水源導(dǎo)出來莱找,注入到種莊稼的田地里酬姆,也就是我們需要有一個(gè)踩水車,而我們的Component則是負(fù)責(zé)踩水車這個(gè)角色奥溺。
2.3 Component
首先我們看下Component類
@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
Context getContext();
RxBus getRxBus();
DaoSession getDaoSession();
}
我們這里定義的是ApplicationComponent辞色,我們在自己的Application類中實(shí)例化:
public App extends Applicaion{
private static ApplicationComponent sAppComponent;
...//省略
@Override
public void onCreate() {
super.onCreate();
initConfig();
}
...//省略
private void initInjector() {
sAppComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this, mDaoSession, mRxBus))
.build();
}
...//省略
}
這里Dagger會(huì)根據(jù)相應(yīng)的注解自動(dòng)使用apt在/app/build/generated/apt/debug/中生成對應(yīng)的DaggerApplicationComponent類。我們觀察一下該類浮定,也就是看下水車的結(jié)構(gòu)相满。
public final class DaggerApplicationComponent implements ApplicationComponent {
private Provider<Context> provideApplicationContextProvider;
private Provider<RxBus> provideRxBusProvider;
private Provider<DaoSession> provideDaoSessionProvider;
private DaggerApplicationComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.provideApplicationContextProvider =
DoubleCheck.provider(
ApplicationModule_ProvideApplicationContextFactory.create(builder.applicationModule));
this.provideRxBusProvider =
DoubleCheck.provider(
ApplicationModule_ProvideRxBusFactory.create(builder.applicationModule));
this.provideDaoSessionProvider =
DoubleCheck.provider(
ApplicationModule_ProvideDaoSessionFactory.create(builder.applicationModule));
}
@Override
public Context getContext() {
return provideApplicationContextProvider.get();
}
@Override
public RxBus getRxBus() {
return provideRxBusProvider.get();
}
@Override
public DaoSession getDaoSession() {
return provideDaoSessionProvider.get();
}
public static final class Builder {
private ApplicationModule applicationModule;
private Builder() {}
public ApplicationComponent build() {
if (applicationModule == null) {
throw new IllegalStateException(
ApplicationModule.class.getCanonicalName() + " must be set");
}
return new DaggerApplicationComponent(this);
}
public Builder applicationModule(ApplicationModule applicationModule) {
this.applicationModule = Preconditions.checkNotNull(applicationModule);
return this;
}
}
}
代碼不多,但是比較混雜壶唤,我們慢慢擼:
我們觀察到Dagger使用在生成相應(yīng)的DaggerApplicationComponent 類時(shí)采用了建造者模式雳灵,其構(gòu)造方法私有意味著并不能直接new出來,而是需要通過建造者類Builder闸盔。而Builder類是DaggerApplicationComponent 中的公共靜態(tài)內(nèi)部類悯辙,其構(gòu)造方法中會(huì)傳入ApplicationModule 并持有它。
那么這樣就清楚了迎吵,首先我們通過建造者類將ApplicationModule 傳入并持有引用躲撰,其次將建造者類作為DaggerApplicationComponent 構(gòu)造方法的參數(shù)傳入DaggerApplicationComponent 類中,這樣DaggerApplicationComponent 就持有了ApplicationModule 击费,也就是持有了依賴提供者拢蛋。這時(shí)候我們可以理解為我們成功建造了水車,并且接入了水源蔫巩。
現(xiàn)在我們仔細(xì)分析一下DaggerApplicationComponent 類谆棱。
首先Dagger獲取被@Providers注解的方法的返回值,使用Provider結(jié)構(gòu)包裹返回值圆仔,生成相應(yīng)的Provider的私有字段垃瞧,然后在initialize方法中,拿到建造者類Builder中持有的applicationModule坪郭。
于此同時(shí)在/app/build/generated/apt/debug/生成被@Providers注解方法的返回值的對應(yīng)的工廠類个从,例如ApplicationModule_ProvideApplicationContextFactory。
我們順著工廠類看下去:
public final class ApplicationModule_ProvideApplicationContextFactory implements Factory<Context> {
private final ApplicationModule module;
public ApplicationModule_ProvideApplicationContextFactory(ApplicationModule module) {
assert module != null;
this.module = module;
}
@Override
public Context get() {
return Preconditions.checkNotNull(
module.provideApplicationContext(),
"Cannot return null from a non-@Nullable @Provides method");
}
public static Factory<Context> create(ApplicationModule module) {
return new ApplicationModule_ProvideApplicationContextFactory(module);
}
}
我們看到工廠類實(shí)現(xiàn)了Factory<T>接口,其實(shí)在深入一層的話嗦锐,我們會(huì)發(fā)現(xiàn)Factory是繼承自Provider接口的嫌松,所以Factory實(shí)際上也是提供者,使用Factory的原因在于利于更好的拓展性。在Factory中傳入相應(yīng)的module奕污,并在get方法中拿取到被@Provider注解的方法返回的具體的對象(詳見:module.provideApplicationContext())萎羔。
我們繼續(xù)返回上層的DaggerApplicationComponent 的initialize方法。我們發(fā)現(xiàn)從工廠類中獲取的對象直接就賦值給了相應(yīng)的Provider字段菊值。
至此外驱,DaggerApplicationComponent 實(shí)現(xiàn)了獲取ApplicationModule中被@Provider注解的相應(yīng)方法的返回對象并使用Provider持有該對象DaggerApplicationComponent 重寫ApplicationComponent 的方法中直接從Provider字段中g(shù)et相應(yīng)的對象就行。就相當(dāng)于我們的水車已經(jīng)順利的水源取水了腻窒。
3.總結(jié)
總而言之,Dagger根據(jù)@Provider直接生成相應(yīng)的工廠類和DaggerApplicationComponent 類磅崭,DaggerApplicationComponent 類持有Module和相應(yīng)的工廠類字段儿子,實(shí)現(xiàn)了從水源取水這一過程。
第二篇比較枯燥砸喻,全是代碼的解讀和分析柔逼。下一篇我們將關(guān)注@Inject是怎樣實(shí)現(xiàn)注入的。