为了介绍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教程一之配置(原)》
《Dagger2教程二之基础使用(原)》
《Dagger2教程三之构造方法带参数的情况(原)》
《Dagger2教程四之多构造方法的情况(原)》
《Dagger2教程五之单例模式(原)》
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/222739.html原文链接:https://javaforall.net
