这几天真心为了学习dagger2花费了很多精力,对于什么@Scope、@Provides、@Component、@Module、@Named之类的关键字还比较好理解,其实关于编译后的dagger源码也都比较好理解,也正是因为读dagger2编译源码知道dagger2不是基于反射来实现的依赖注入,而是通过apt包生成对应工厂类来实现依赖注入。既然这些都知道了按理说使用dagger2应该不是什么难题了,的确,一般的使用是没什么问题了,但是无意中看见dagger2的组件依赖以及子组件的文章,文章写得很好,就是不是很好理解,就是那种懂得能看懂,不懂得很难懂得那种类型,于是决定自己在这里总结一下。而这篇文章,就是主要围绕“多Module组件使用”、”组件依赖”、“子组件”这三部分的使用和区分来进行讲解。
1、多Module的组件使用
我们知道Component的作用是连接Module和@Inject的(其实也可以单纯的连接两个@Inject,个人觉得连接@Module和@Inject的用法更加常规),那么存在一个Module对应一个Component的情况,也就存在多个Module对应一个Component的情况,那么废话不多说,直接贴代码。
AppModule.class
@Module
public class AppModule {
private MyApplication myApplication;
public AppModule(MyApplication myApplication){
this.myApplication = myApplication;
}
@Singleton
@Provides
public Context providesContext(){
return myApplication;
}
}
MultiTestModule
@Module
public class MultiTestModule {
public MultiTestModule(){
}
@Singleton
@Provides
public String providesStr(Context context){
return "string from myapplication" + context.getCacheDir().getPath();
}
}
MultiTestComponent.class
@Singleton
@Component(modules = {AppModule.class, MultiTestModule.class})
public interface MultiTestComponent {
void inject(DaggerActivity activity);
}
DaggerActivity.class
@Inject String mutliStr;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerMultiTestComponent.builder()
.appModule(new AppModule((MyApplication)this.getApplication()))
.multiTestModule(new MultiTestModule())
.build()
.inject(this);
Log.i("yoryky", "string from multistr: " + mutliStr );
}
以上代码是指贴出了核心代码,当然就依照这些代码,已经可以在本地自己做测试了,不过文章最后还是会贴出来源码地址的。
有一点需要注意是,这里的AppModule和MultiTestModule两个Module共同对应一个Component,同事要注意这两个Module的声明周期的都是相同的@Singleton,这一点区别于后面要讲的组件依赖和子组件。至于多Module的使用场景是很多的,一个典型就是你想有自己的Application对应的AppModule同时,有需要一个NetServer进行网络访问,但是这个使用NetServer的对象中,又可能需要AppModule中实现的依赖注入,那么就可以在NetServer对应的的
2、组件依赖的使用
组件依赖同多Module对应一个Component的情况一样,也是存在多个Module情况,不过组件依赖的多Module对应多个Component,也直接先上代码吧。
AppModule.class
@Module
public class AppModule {
private MyApplication myApplication;
public AppModule(MyApplication myApplication){
this.myApplication = myApplication;
}
@Singleton
@Provides
public Context providesContext(){
return myApplication;
}
}
AppComponent.class
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
Context context();
}
DependTestModule.class
@Module
public class DependTestModule {
public DependTestModule(){
}
@DependScope
@Provides
public DaggerUtil providesDaggerUtil(Context context){
return new DaggerUtil(context);
}
}
DependTestComponent.class
@DependScope
@Component(dependencies = {AppComponent.class},modules = {DependTestModule.class})
public interface DependTestComponent {
void inject(DaggerActivity activity);
}
DaggerActivity.class
@Inject DaggerUtil daggerUtil;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerDependTestComponent.builder()
.appComponent(((MyApplication)getApplication()).getAppComponent())
.dependTestModule(new DependTestModule())
.build()
.inject(this);
daggerUtil.test();
}
以上代码可以看出,DependTestComponent依赖AppComponent,这种依赖的实现在代码上表现为
在DependTestComponent中标明依赖关系
dependencies = {AppComponent.class}
然后在AppComponent中暴露出来提供给DependTestComponent的依赖
Context context();
其中这里的context()方法名随意写,如果AppModule中对应实现方法有参数也不用写参数,关键是写好返回参数Context就行,这样DependTestModule的providesDaggerUtil方法中的Context就通过AppModule依赖注入,就不用手动传参数了。
同事还应该注意的就是,AppModule和DependTestModule的Scope不一样,这里贴出来DependScope的代码吧。
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface DependScope {
}
3、子组件的使用
其实子组件和依赖组件的作用,个人感觉大同小异,都是方便使用其它Module中的实现,以便完成自己Module中的依赖注入,这句话可能也是懂得懂,不懂得不懂,还是看代码吧。
ChildModule.class
@Module
public class ChildModule {
public ChildModule(){
}
@ChildScope
@Provides
public DaggerUtil providesDaggerUtil(Context context){
return new DaggerUtil(context);
}
}
ChildComponent.class
@ChildScope
@Subcomponent(modules = {ChildModule.class})
public interface ChildComponent {
void inject(DaggerActivity activity);
}
ParentModule.class
@Module
public class ParentModule {
private Context context;
public ParentModule(Context context){
this.context = context;
}
@ParentScope
@Provides
public Context providesContext(){
return this.context;
}
@ParentScope
@Provides
public User providesUser(){
Child child = new Child();
return new User(child);
}
}
ParentComponent.class
@ParentScope
@Component(modules = {ParentModule.class})
public interface ParentComponent {
ChildComponent newChildComponent(ChildModule childModule);
}
DaggerActivity.class
@Inject User user;
@Inject DaggerUtil daggerUtil2;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/** 测试子组件*/
ParentComponent parentComponent = DaggerParentComponent.builder()
.parentModule(new ParentModule(this))
.build();
parentComponent.newChildComponent(new ChildModule()).inject(this);
user.test();
daggerUtil2.test();
}
从代码可以看出子组件和组件依赖一样,父子组件的Scope不能一样(定义同DependScope,改个名字而已),但是不一样的点在与子组件可以使用父组件所有的Module实现进行依赖注入,同时在构建子组件时的代码实现方式也和构建组件依赖时不一样。
实现子组件很简答,ParentComponent中显示声明子组件
ChildComponent newChildComponent(ChildModule childModule);
其中方法名随意些,只是传参和返回参数要求对应写。
自组件ChildComponent中通过Subcomponent来完成子组件身份的说明
@Subcomponent(modules = {ChildModule.class})
使用子组件时,其实是通过父组件newChildComponent来完成注入的(就是我们在父组件中定义的那个方法),这一点看代码。
于是乎,子组件的说明也就结束了。
4、源码地址
本文关于组件实现方式及使用其实算是写的很详细了,但是还是把源码地址贴出来吧,反正就是自己平时的学习demo。
https://github.com/Yoryky/AndroidDemo.git
5、参考文献
这里的参考文献,不一定是对本文有帮助的,但是一定都是与dagger2相关的,因为dagger2学习曲线稍微陡峭一点,这些文章这几天算是帮了我大忙,这里贴出来就算是帮着推广下吧。
1、Dagger2从入门到放弃再到恍然大悟:
http://www.jianshu.com/p/39d1df6c877d
3、更清晰的Dagger2 + MVP 架构:
http://www.jianshu.com/p/a1613d94ddbe
4、dagger2:组件依赖和子组件的区别
http://www.jianshu.com/p/5ce4dcc41ec7