接着上一篇Dagger2 使用总结(一)继续总结Dagger2的使用方法。
Component接口的复用
我们可以适当地复用Component接口,从而使逻辑更加简洁且减少不必要的重复工作,复用一般使用dependencies
或者@Subcomponent
,这两者比较相似,要注意区分,先看实现再总结吧:
依赖 dependencies
场景:现在有Vegetable
抽象类和其两个子类Tomato
和Potato
,项目中可能较多地方都需要注入这两个类的对象。
这时候我们可以建立BaseComponent
接口,其他需要使用这两个对象的Component接口依赖于这个BaseComponent
接口即可注入这两个对象,如下:
- 新建
Vegetable
、Tomato
、Potato
和VegetableModule
public abstract class Vegetable {
public abstract void print();
}
public class Tomato extends Vegetable{
@Override
public void print() {
Log.d(TAG, "This is a tomato");
}
}
public class Potato extends Vegetable {
@Override
public void print() {
Log.d(TAG,"This is a potato");
}
}
@Module
public class VegetableModule {
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ProvideTomato{}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ProvidePotato{}
@Provides
@ProvideTomato
Vegetable provideTomato() {
return new Tomato();
}
@Provides
@ProvidePotato
Vegetable providePotato() {
return new Potato();
}
}
这些实现和注解在上一篇文章中都有说明,如果不了解可以回去翻一下。
- 新建
BaseComponent
接口
@Component (modules = VegetableModule.class)
public interface BaseComponent {
@VegetableModule.ProvideTomato Vegetable getTomato();
@VegetableModule.ProvidePotato Vegetable getPotato();
}
在这里使用getXXX
方法可以暴露这个接口可以获得的对象,以使依赖其的接口可以获得该对象,如果不需要暴露则可不要编写getXXX
方法以保持逻辑严谨。比如如果不需要暴露Potato
对象,可以将getPotato()
方法删除,这样即便依赖了BaseComponent
接口,也无法获得Potato
对象。
现在可以编译项目以使build目录下生成相关文件。
- 在
MainActivity
中实现依赖和注入
@Inject //属性注入对象
@VegetableModule.ProvideTomato
public Vegetable tomato;
@Inject //属性注入对象
@VegetableModule.ProvidePotato
public Vegetable potato;
@Component (dependencies = BaseComponent.class) //这里使用了dependencies依赖了BaseComponent接口
interface MainActivityComponent {
void inject(MainActivity activity);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivity_MainActivityComponent
.builder()
.baseComponent(DaggerBaseComponent.builder().build()) //依赖的接口要在这里配置下
.build()
.inject(this);
tomato.print();
potato.print();
}
这样就省去了直接编写Component接口的实现,直接使用dependencies
依赖即可。这种依赖方式的特点是可以实现暴露出的接口,同时自身也可以扩展自己的实现。
- 拓展
依赖关系也可以实现多依赖,容易理解就不解释了,看代码:
@Component (dependencies = {BaseComponent.class, OtherComponent.class}) //多依赖
interface MainActivityComponent {
void inject(MainActivity activity);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivity_MainActivityComponent
.builder()
.baseComponent(DaggerBaseComponent.builder().build())
.otherComponent(DaggerOtherComponent.builder().build()) //这里注意也要配置下
.build()
.inject(this);
tomato.print();
potato.print();
}
@Subcomponent
和dependencies
区别在于,不需要父Component暴露出接口,也可以直接注入父Component中可注入的对象,有点像继承关系。
为方便对比,还是刚刚的例子,看看代码实现:
- 新建
Vegetable
、Tomato
、Potato
和VegetableModule
同上例。
- 新建
BaseComponent
@Component (modules = VegetableModule.class)
public interface BaseComponents {
MainActivityComponent plus(); //这里加一个返回SubComponent的方法
}
- 实现SubComponent
@Subcomponent (modules = FruitModule.class) //这里的@Subcomponent表示这是一个SubComponent接口
public interface MainActivityComponent {
void inject(MainActivity activity);
}
- 在
MainActivity
注入对象
DaggerDagger2Components_BaseComponents
.builder()
.build()
.plus() //这里返回MainActivityComponent
.inject(this);
这里只列出改变的地方,其他代码同上例。
总结
dependencies
和@SubComponent
都是实现了Component接口的复用,使用dependencies
需要在父Component中暴露出需要注入的类(比如getXXX
),而使用@SubComponent
不需要暴露类,而需要直接提供一个获取SubComponent的方法。
为避免混乱,建议一个模块仅使用一种复用方式:
-
dependencies
适用于部分父Component中对象需要对子Component隐藏,或者公共注入类不多的情况。 -
@SubComponent
适用于父Component中公共注入类较多且不用隐藏的场景。
@Scope和@Singleton注解
我们可以用@Scope
管理注入类的作用域,@Singleton
是@Scope
的默认实现方式。
待补充。
网友评论