本文旨在学习MVP+retrofit+rxAndroid(rxJava)+dagger2框架,已经争取到作者的支持,作者的github地址是:https://github.com/laotan7237/EasyReader,作者原csdn地址是:http://blog.csdn.net/laotan7237/article/details/68946797,感谢作者的支持!
现在我们已经将retrofit2+rxJava异步请求和响应式框架了解清楚了,接下来我们要探究最后也是最为复杂的依赖注入框架dagger2,在前面我们看到代码里LoadingBaseActivity中持有的T泛型的mPresenter上有一个@Inject的@注解,这个注解我们在MovieDetaiPresenterImpl当中也看到了构造方式上有一个对应的@Inject,除此外inject这个package下面还有其他的很多内容帮助我们实现依赖注入,具体而言,DoubanMovieDetailPresenterImpl当中的DoubanService的实例化方式这套机制到底是如何运行的,使我们想要理解的问题。
dagger2的基础知识包括几个@注解,@Inject,@component,@Provides,@Module,@Scope和@Qualifier。@Inject分别写在需要注入的类实例和该类的某个构造方法上,dagger在需要实例化的地方(如在Activity里)去找对应的这个类里也带有@Inject注解的构造方法,帮助你构造这个实例,这种方式与Butterknife的@Bind类似。
以阅读的代码为例,我们分析LoadingBaseActivity中看到了对继承自BasePresenter的泛型T实例mPresenter上方有一个@Inject,这意味着针对每一个指定了T泛型的LoadBasePresenter实例会在项目中去寻找同样注解了@Inject的提供T类型的构造方法,找到后,自动将T型实例构造出来,我们分析的DoubanMovieDetail中,T被指定为MovieDetailPresenterImpl,我们确实的再这个类的构造方法上看到了@Inject注解。我们容易想到,针对同一个类的实例可能在不同的地方要使用不同的构造方法,这时候dagger要怎么确定使用哪一个构造,这个问题是dagger已经想到并且解决了的,dagger将它称作“注入迷失”,后面我们用到的@Scope和@Qualifier能够解决构造方法的选择问题,并能够为注入方式做一些限定,譬如构造出单例。
最难理解但最常见的注解是“@Component,@Provides,@Module”这一组,使用@Module注解的类里定义需要实例化对象的提供方法,使用provide作为方法名的起始,这样dagger在识别到这些方法的时候会去创建相应的工厂方法,在这些方法名上我们采用@Provides注解,表明方法返回类型的对象由该方法实例化,将@Module注解的类注入到需要使用的地方是@Component,@component注解接口,在注解处申明需要注入到目标类里的Module,语法格式为@Component(mudules={XXXModule.class}),接口中定义接口方法inject,这个方法在需要注入的地方被调用。
@Singleton
@Component(modules = { DoubanHttpModule.class})
public interface MovieDetailComponent {
void injectMovieDetail(MovieTopDetailActivity movieTopDetailActivity);
}
public class MovieTopDetailActivity extends LoadingBaseActivity<DoubanMovieDetailPresenterImpl> implements DoubanMovieDetailPresenter.View
@Override
protected void initInject() {
DaggerMovieDetailComponent.builder()
.doubanHttpModule(new DoubanHttpModule())
.build().injectMovieDetail(this);
}
我们分析的代码中MovieTopDetailActivity中调用了该方法用于注入MovieDetailConponent当中所包含的Module
我们在MovieTopDetailActivity中看到他是继承自持有DoubanMovieDetailPresenterImpl类型mPresenter的LoadingBaseActivity,在DoubanMovieDetailPresenterImpl里持有一个DoubanService实例,但是可以看到这个Service没有被new的方式实例化,这里的Service是依靠注入的方式由dagger帮我们实例化的,这里我们理解一下“Component类似于一个注射器,把Module注入到使用的地方去”,在initInject这个方法里我们使用Component(DaggerMovieDetailComponent是有Dagger自动生成的,生成标准是有@Component注解)将DoubanHttpModule注入到this(这个Activity)当中,在DoubanHttpModule有一个provideDoubanService方法,这代表着所有我们需要用到DoubanService的时候dagger都会调用这个方法帮我们构造一个实例来,可以注意到,在构造这个Service的实例时传入的参数Retrofit实例也是由dagger帮助我们实例化的,使用provideDoubanRetrofit方法,这里我们看到了一个@注解——@DoubanUrl,跟进去后我们发现这是一个@Qualifier注解,这个注解帮助dagger找到具体对应的实例构造方法,这里需要传入的Retrofit对象必须保证是由DoubanService.API_DOUBAN这个url作为参数构造的,需要与其他的Retrofit对象区分开来(在其他的Module里有很多类型的Retrofit对象),可以利用在使用处和构造方法处分别添加同一个@注解(@Qualifier类型),来防止注入迷失。
@Module
public class DoubanHttpModule extends BaseHttpModule {
@Singleton
@Provides
@DoubanUrl
Retrofit provideDoubanRetrofit(Retrofit.Builder builder, OkHttpClient client) {
return createRetrofit(builder, client, DoubanService.API_DOUBAN);
}
@Singleton
@Provides
DoubanService provideDoubanService(@DoubanUrl Retrofit retrofit) {
return retrofit.create(DoubanService.class);
}
}
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface DoubanUrl {
}
在@Qualifier类型的注解中,需要指定@Qualifier、@Documented和@Retention(RUNTIME)这三项内容。
未完待续