技术债Dagger2:Android篇(下)进一步理解Dagger"/>
出来混迟早要还的,技术债Dagger2:Android篇(下)进一步理解Dagger
前言
警告!这不是一个干货的文章!
个人认为,学技术不宜太浮躁。对于一项技术一味地追求干货其实并不一定有用,货太干容易噎着,哈哈~不如循序渐进慢下来,一点点去体会技术的前因后果。(这个系列适合于:了解但没有在项目里大规模应用Dagger2的读者)
出来混迟早要还的,技术债Dagger2:基础篇
出来混迟早要还的,技术债Dagger2:Android篇(上)
出来混迟早要还的,技术债Dagger2:Android篇(中)@Scope、@Singleton
本以为阅读一些文档,写一些Demo就能驾驭工作中的项目...我错了,我再也不会有这么愚蠢的想法了... 这么多依赖关系,谁扛得住啊!所以还是一点点来吧。
正文
前俩篇文章过后,我猜大家对下面的代码已经很熟悉了:
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {void inject(MainActivity mainActivity);SharedPreferences getSharedPrefs();
}@Module
public class AppModule {Application application;public AppModule(Application application) {this.application = application;}@ProvidesApplication providesApplication() {return application;}@Provides@Singletonpublic SharedPreferences providePreferences() {return application.getSharedPreferences(DATA_STORE,Context.MODE_PRIVATE);}
}DaggerAppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)) .build();
复制代码
很基本,很简单的Dagger应用。不过大家有没有感觉到这个appModule(new AppModule(this))
特别烦?安利我用的时候,说依赖注入,看不见new。我哼哧哼哧写这么多,这不还是new出来的?
那么问题来了,是不是可以不需要appModule(new AppModule(this))
呢?当然可以。用过Dagger-Android
的朋友,肯定很清楚,的确看不到任何new。那么这篇文章,咱们就来看看如何彻底不用new。
当然这也是Dagger-Android的原理
@Component.Builder
做这一切的前提是这个注解。这个注解是干啥的呢?说白了,给Component提供Module的依赖。
咱们先来想一个问题,下面代码存在的意义:
DaggerAppComponent appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)) .build();
复制代码
Dagger为我们所需的依赖生成实例,那么必然需要构建整个依赖关系网。Dagger就算是再神奇,也不可能凭空把整个我们所需要依赖关系构建出来,所以需要我们适时的“提供和引导”。那么new AppModule(this)
就是给Dagger进行提供,因为从我们上述的代码中,Dagger是不知道该怎么去实例化这个AppModule
,因此需要我们对其进行提供。
那么话又说回来,我们在上述的代码中,告诉它如何去实例化AppModule
,不就可以避免我们手动去new AppModule(this)
了么?
没错,@Component.Builder
就是做这个的。
累死了,绕了一圈不知道大家理没理解@Component.Builder存在的含义了。
AppModule(Application application)
对于我们的AppModule
来说,实例化它的关键是如何提供一个Application
。
public AppModule(Application application) {this.application = application;
}
复制代码
对于Dagger也是如此,它不能实例化AppModule
的原因是它不知道或者说没办法去获取一个Application
实例。因此,对于Dagger来说,我们应该给它提供Application
的实例,而非AppModule
。
开始改造
改造需要一步步来:第一步,我们使用@Component.Builder
去改造AppComponent
:
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {void inject(MainActivity mainActivity);SharedPreferences getSharedPrefs();// 改造内容@Component.Builderinterface Builder {AppComponent build();// 此时还未改造这行代码Builder appModule(AppModule appModule);}
}
复制代码
现在我们告诉了Dagger,你要以
@Component.Builder
注解的接口那样去实例化我们所需的AppComponent
。
是不是发现这里添加的方法和DaggerAppComponent
生成的代码很像?没错Dagger默认实例化AppComponent
就是以这种代码进行的。
不过,对于我们这个AppModule
来说,我们不需要关系它是怎么初始化(因为我们只需要它所提供给我们的依赖)。对于Dagger来说也是如此: Dagger想要为我们提供被@Provides
标注的依赖,只需要拥有Application
实例即可。因为只要拥有Application
实例Dagger就有办法实例化AppModule
,直接new即可。
所以这里我们需要一种方式来告诉Dagger:我要提供给你,在@Module
中需要的内容。对于咱们的这个demo来说,咱们需要用一种方式把Dagger所需要的Application
给他。
而做到这一点的就是@BindsInstance
。
@BindsInstance
按照官网的介绍,此注解用于标识Component Builder/SubComponent Builder中的某个方法,该方法允许将实例绑定到Component中。
所以对于我们的AppModule
来说,它只需要提供@Provides
的内容就可以了!,它所需要的,Dagger会按照我们的“指示”,注入进来。也就是这个样子:
@Module
public class AppModule {@Provides@Singleton// 外部传入Application实例(Dagger会按照我们的“指示”,注入进来)public SharedPreferences providePreferences(Application application) {return application.getSharedPreferences("store", Context.MODE_PRIVATE);}}
复制代码
而我们的AppConponent
这样就可以了:
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {void inject(MainActivity mainActivity);SharedPreferences getSharedPrefs();@Component.Builderinterface Builder {AppComponent build();@BindsInstance // 此时的application就会被,注入到AppModule的providePreferences方法中Builder application(Application application); }
}
复制代码
build过后,我们初始化DaggerAppComponent
,只需如此写:
DaggerAppComponent appComponent = DaggerAppComponent.builder().application(this).build();
复制代码
那么Dagger是如何为我们生成DaggerAppComponent
的呢?
public final class DaggerAppComponent implements AppComponent {private Provider<Application> applicationProvider;private Provider<SharedPreferences> providePreferencesProvider;private DaggerAppComponent(Builder builder) {initialize(builder);}public static AppComponent.Builder builder() {return new Builder();}@SuppressWarnings("unchecked")private void initialize(final Builder builder) {this.applicationProvider = InstanceFactory.create(builder.application);this.providePreferencesProvider =DoubleCheck.provider(AppModule_ProvidePreferencesFactory.create(builder.appModule, applicationProvider));}@Overridepublic void inject(MainActivity mainActivity) {}@Overridepublic SharedPreferences getSharedPrefs() {return providePreferencesProvider.get();}private static final class Builder implements AppComponent.Builder {private AppModule appModule;private Application application;@Overridepublic AppComponent build() {if (appModule == null) {this.appModule = new AppModule();}if (application == null) {throw new IllegalStateException(Application.class.getCanonicalName() + " must be set");}return new DaggerAppComponent(this);}@Overridepublic Builder application(Application application) {this.application = Preconditions.checkNotNull(application);return this;}}
}
复制代码
对于AppModule
来说,只是简单的new出来,当我们需要@Provides
时,只是将所需的application
传进去。而我们的application
以成员变量的身份呆在了DaggerAppComponent
“体内”。
尾声
这篇内容,其实并不是为了去讲@Component.Builder
和@BindsInstance
。而是尽可能的通过它们,来加深大家去Component和Module的理解。去感受Dagger的实现,更好的去理解依赖注入。对与我们而言,需要用其形,学其神。
这样我们才不会受制于框架,而是驾驭框架。
我是一个应届生,最近和朋友们维护了一个公众号,内容是我们在从应届生过渡到开发这一路所踩过的坑,以及我们一步步学习的记录,如果感兴趣的朋友可以关注一下,一同加油~
转载于:
更多推荐
出来混迟早要还的,技术债Dagger2:Android篇(下)进一步理解Dagger
发布评论