Dagger2教程六之Component的组织方法(原)
Posted 工程师阿杜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dagger2教程六之Component的组织方法(原)相关的知识,希望对你有一定的参考价值。
为了介绍Dagger2的使用,我们搭建了一个Demo来逐步分析,大家可以在 这里下载源码( 这个源码与之前的五个小节源码不同)(https://github.com/dushaofeng/DaggerDemo2.git)。上一节我们介绍了 《Dagger2教程五之单例模式》,这一节我们来介绍Component的组织方法。
所谓Component组织方法,也就是我们工程中的Component该如何分布和结合。
对于一款APP来说,一些基础的服务类比如全局Log、图片加载器、网络请求器、缓存器等应该做到全局单例,而对某个Activity或者Fragment来说又有自己的单例或者非单例的对象,那么这种情况下该如何组织我们的注入结构呢?
我们现在知道Component是连接注入类和目标类的桥梁,那么最简单的结构应该是这样的:
1、Application负责创建全局的单例或者非单例注入类的Component对象
2、Activity或Fragment在继承Application提供的Component基础上扩展自己的Component接口
那么具体该如何操作呢?
Dagger2给我们提供两种方法来实现注入继承。
一、使用dependencies属性实现继承注入
如果对比源码看的话, 请将源码分支切换到UseDependencies分支。
1.1、准备ApplicationBean对象
我们创建一个ApplicationBean对象用来作为目标类,准备将其注入到应用中: public class ApplicationBean
private String name = null;
public ApplicationBean()
name = "AppBean";
public String getAppBeanName()
return name;
1.2、准备APP级别的Module对象
然后创建ApplicationModule用来将其注入到目标类,并且我们标记了Singleton准备将其作为单例模式注入: @Module
public class ApplicationModule
//作为单例模式注入app
@Singleton
@Provides
ApplicationBean privoderAppBean()
return new ApplicationBean();
1.3、准备APP级别的Component对象
相应的,我们创建ApplicationComponent用来连接ApplicationModule和Application: @Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent
void inject(DaggerApplication application);
//说明将BeanForApplication开放给其他Component使用
ApplicationBean providerAppBean();
在这里请注意两点:
1、由于我们设计要将ApplicationBean作为单例注入,因此ApplicationComponent也需要标记@Singleton标识
2、我们在ApplicationComponent中提供了一个返回值为ApplicationBean对象的方法声明, 它的作用是将该Component中的ApplicationBean对象暴露给其他Component使用,相当于AIDL语言中的方法声明。
1.4、注入Application
我们需要在Application中完成两个任务:1、将ApplicationBean注入到Application内部
2、将ApplicationComponent对象共享给Activity或者其他类
具体实现如下:
public class DaggerApplication extends Application
private ApplicationComponent mAppComponent;
@Inject
ApplicationBean mAppBean1;
@Inject
ApplicationBean mAppBean2;
@Override
public void onCreate()
super.onCreate();
if (mAppComponent == null)
mAppComponent = DaggerApplicationComponent.create();
mAppComponent.inject(this);
Log.d("Dagger", "Application mAppBean1:" + mAppBean1);
Log.d("Dagger", "Application mAppBean2:" + mAppBean2);
public ApplicationComponent getAppComponent()
return mAppComponent;
在这里我们注入了两次ApplicationBean对象,并在注入完成后打印出它们的地址用于观察是否实现了单例的功能。
1.5、准备ActivityBean对象
我们再创建一个Activity的Bean对象用于观察注入情况: public class ActivityBean
private String name = null;
public ActivityBean()
public String getAppBeanName()
return name;
1.6、准备Activity的Module对象
Activity的Module应该提供ActivityBean的注入方式: @Module
public class ActivityModule
@Provides
ActivityBean providerActivityBean()
return new ActivityBean();
1.7、准备Activity的Component对象
我们要在Activity的Component中继承ApplicationComponent,也就是要 让Activity的Component不仅可以从ActivityModule中查找注入类,还要能从ApplicationModule中查找到注入类: @ForActivity
@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface ActivityComponent
void inject(MainActivity activity);
void inject(MainActivity.OtherClass otherClass);
这个Component的写法有三处与之前的写法不同的地方:
1、添加了ForActivity的修饰,而这个ForActivity就是我们自定义的Scope的一种,根据之前我们的介绍, 他的作用和Singleton是一样的,用于限制该Component的使用范围:
@Scope
@Retention(RUNTIME)
public @interface ForActivity
为什么要添加这个修饰呢?因为当前Component所继承的ApplicationComponent中包含Singleton的注释,
所以ApplicationComponent的子类Component的作用范围不能高于ApplicationComponent的作用范围,因此需要对ActivityComponent也添加Scope的限定。
2、Component中多了"dependencies = ApplicationComponent.class"的注释,它的作用就是告诉Dagger, 当前Component依赖于ApplicationComponent,在查找注入类的时候不仅要在ActivityModule中查找,还需要去ApplicationComponent中的Module中查找。
3、我们提供了两个inject()方法,作用是要将该Component同时注入到两个对象中,这在之前的介绍中使用过。
1.8、设计Activity对象
我们接下来就要在Activity中同时注入ActivityBean和ApplicationBean对象了,并且ApplicationBean还是全局单例的模式,为了扩展测试,我们在Activity中还创建了一个OtherClass,也将ActivityBean和ApplicationComponent都注入进去进行观察: public class MainActivity extends AppCompatActivity
@Inject
ApplicationBean applicationBean1;
@Inject
ApplicationBean applicationBean2;
@Inject
ActivityBean activityBean;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerApplication application = (DaggerApplication) getApplication();
ApplicationComponent applicationComponent = application.getAppComponent();
ActivityComponent activityComponent = DaggerActivityComponent.builder().applicationComponent(applicationComponent).build();
activityComponent.inject(this);
Log.d("Dagger", "Activity activityBean:" + activityBean);
Log.d("Dagger", "Activity applicationBean1:" + applicationBean1);
Log.d("Dagger", "Activity applicationBean2:" + applicationBean2);
OtherClass otherClass = new OtherClass();
class OtherClass
@Inject
ApplicationBean applicationBean1;
@Inject
ApplicationBean applicationBean2;
@Inject
ActivityBean activityBean;
public OtherClass()
DaggerApplication application = (DaggerApplication) getApplication();
ApplicationComponent applicationComponent = application.getAppComponent();
ActivityComponent activityComponent = DaggerActivityComponent.builder().applicationComponent(applicationComponent).build();
activityComponent.inject(this);
Log.d("Dagger", "OtherClass activityBean:" + this.activityBean);
Log.d("Dagger", "OtherClass applicationBean1:" + this.applicationBean1);
Log.d("Dagger", "OtherClass applicationBean2:" + this.applicationBean2);
1.9、结果分析
我们运行之后打印出来的Log如下图:我们来分析Log的表现:
1、Application中注入的mAppBean1和mAppBean2以及Activity中注入的applicationBean1、applicationBean2还有OtherClass中注入的applicationBean1、applicationBean2这六个对象的地址都是95c5354
分析:
1、在Activity和OtherClass中我们可以获取到ApplicationBean对象,说明我们当前的注入方式完成了"Activity从Application继承Component进行注入"的任务
2、我们不仅在APP的全局都获取到了ApplicationBean对象,而且得到的都是单例对象,这说明我们在ApplicationModule中对ApplicationBean进行单例注入的方式在全局都是有效的
2、Activity中的activityBean和OtherClass中的activityBean对象地址不同
分析:
ActivityBean对象在Activity中和OtherClass中分别注入了两次,所以这两次注入是独立的,它们注入的ActivityBean对象是不同的
至此,该注入方式我们就介绍完毕,下面我们来介绍另一种继承的方式。
二、使用Subcomponent的方式进行继承注入
如果对比源码看的话, 请将源码分支切换到UseSubcomponent分支。
2.1、如何注入
该方式和上面的方式区别之处只有三个地方:
1、改造Activity的Component对象
我们需要先来改造Activity的Component对象,也就是ActivityComponent,需要将其改写为如下的方式: @ForActivity
@Subcomponent(modules = ActivityModule.class)
public interface ActivityComponent
void inject(MainActivity activity);
void inject(MainActivity.OtherClass otherClass);
它与之前的方式的区别有两点:
1、不再使用@Component而使用@Subcomponent来注释
2、删除了"dependencies = ApplicationComponent.class"语句
2、改造Application的Component对象
然后我们来改造Application的Component对象也就是ApplicationComponent,将其改造成如下方式: @Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent
//注入DaggerApplication
void inject(DaggerApplication application);
//说明将BeanForApplication开放给其他Component使用
ApplicationBean providerAppBean();
ActivityComponent activityComponent();
这里的改造只是多了一句声明:ActivityComponent activityComponent()
3、改造Activity中的注入方式
我们还需要改造Activity和OtherClass中的注入方式,改造成如下方式(Activity和OtherClass的注入方式相同): DaggerApplication application = (DaggerApplication) getApplication();
ApplicationComponent applicationComponent = application.getAppComponent();
applicationComponent.activityComponent().inject(this);
然后就完成了所有改造,运行结果如下:
这个结果与dependencies的方式结果是一致的,说明两种注入方式都达到了Component继承的目的。
三、dependencies与Subcomponent注入方式的区别
这两种方式的区别其实在Activity注入时就可以看出来,我们再次贴出它们的对比:dependencies方式:
DaggerApplication application = (DaggerApplication) getApplication();
//获取ApplicationComponent对象
ApplicationComponent applicationComponent = application.getAppComponent();
//用ActivityComponent对象进行注入
ActivityComponent activityComponent = DaggerActivityComponent.builder().applicationComponent(applicationComponent).build();
activityComponent.inject(this);
Subcomponent方式:
DaggerApplication application = (DaggerApplication) getApplication();
ApplicationComponent applicationComponent = application.getAppComponent();
//用ApplicationComponent对象进行注入
applicationComponent.activityComponent().inject(this);
结果发现,dependencies方式中,我们最终调用的是ActivityComponent对象中的inject()方法,而Subcomponent方式中,我们最终调用的是ApplicationComponent的inject()方法。
从Component的注释上我们也可以看到这个区别:
dependencies方式:
//ApplicationComponent
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent
......
//ActivityComponent
@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface ActivityComponent
......
Subcomponent方式:
//ApplicationComponent
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent
......
ActivityComponent activityComponent();
//ActivityComponent
@Subcomponent(modules = ActivityModule.class)
public interface ActivityComponent
......
对比中我们发现,
dependencies中Component强调的是在子类Component依赖于某个Component(子类为主角),而Subcomponent中强调的则是在父类Component中提供某个子类的Component(父类为主角)。
四、如何选择两种继承方式
那么该如何选择这两种继承方式呢?在Stackoverflow中就有人提出了这样的问题(http://stackoverflow.com/questions/29587130/dagger-2-subcomponents-vs-component-dependencies),简单理解就是:
dependencies方式让Component之间更加独立,结构更加清晰,也更利于解耦。
所以该如何选择是否已经有了答案呢?
至此,Dagger2系列介绍就全部结束,下课。
我们再次列出本系列所有的总结:
以上是关于Dagger2教程六之Component的组织方法(原)的主要内容,如果未能解决你的问题,请参考以下文章