Dagger2 系列文章
Dagger2 知识梳理(1) - Dagger2 依赖注入的两种方式
Dagger2 知识梳理(2) - @Qulifier 和 @Named 解决依赖注入迷失
Dagger2 知识梳理(3) - 使用 dependencies 和 @SubComponent 完成依赖注入
Dagger2 知识梳理(4) - @Scope 注解的使用
一、前言
在 Dagger2 知识梳理(1) - Dagger2 依赖注入的两种方式 中,我们介绍了两种依赖注入的方式,其中第二种是通过给注入器Component指定Module,再由Module提供创建实例的方法,来实现依赖注入,这是一种“自给自足”的方式,在这种情况下,我们的Component是这么声明的:
指定 Module
除此之外,还有另外两种方式,让
Component可以通过其他的Component完成依赖注入,可以划分为:依赖方式 和 继承方式。
- 通过依赖方式实现时,需要在
Component中指定它所依赖的Component名字:
依赖方式下的 Component
而被依赖的Component需要声明它可以提供哪些类的实例化,因此它需要在Component中声明一些返回值为这些类的方法:
依赖方式下的被依赖 Component
- 通过继承方式时实现时,子
Component类需要用@SubComponent声明,这种情况下,它一般类似于下面这样:
继承方式下的子 SubComponent
并且我们不能直接创建该Component的实例来完成依赖注入,而是需要由父Component实例提供一个getXXX来将这个SubComponent返回给使用者,SubComponent自动拥有了父Component注入对象的能力。
继承方式下的父 Component
依赖方式和继承方式的共同点就是,它们都是通过别的Component来完成依赖注入的。下面,我们先通过两个简单的例子,来演示如何使用这两种方式完成注入,这篇文章的完整代码可以从 Dagger2Sample 的第三章获取。
二、使用依赖方式完成注入
2.1 定义被依赖的 DependencyComponent
当采用“依赖方式”来实现时,首先需要定义一个被依赖的Component,我们用DependencyComponent来实现,它可以提供一个数据源,即DependencySource:
public class DependencySource {
public String getData() {
return "获取到来自依赖 Component 的数据";
}
}
和前面介绍的一样,该数据源通过一个Component和一个Module来提供:
@Component(modules = DependencyModule.class)
public interface DependencyComponent {
DependencySource getDependencySource();
}
@Module
public class DependencyModule {
@Provides
DependencySource provideDependencySource() {
return new DependencySource();
}
}
注意上面的DependencyComponent,和前面不同,我们不在它里面声明一个inject接口,而是声明了一个getDependencySource接口,返回值为DependencySource,表示可以给被它依赖的Component提供DependencySource这种类型的实例。
2.2 定义依赖 DependencyComponent 的 SourceComponent
接下来,我们创建一个SourceComponent:
@Component(dependencies = DependencyComponent.class)
public interface SourceComponent {
public void inject(DataRepository dataRepository);
}
在Component注解中,采用dependencies来指明它所依赖的Component,接下来,创建一个DataRepository,通过依赖注入的方式来实例化它的DependencySource成员变量,具体的操作步骤为:
- 通过
@Inject声明需要注入的变量mDependencySource - 点击
make编译 - 通过
DaggerDependencyComponent实例化依赖的DependencyComponent - 创建
DaggerSourceComponent,在构造的过程中,传入第二步中的DependencyComponent - 调用
DaggerSourceComponent的inject方法完成注入
public class DataRepository {
@Inject
DependencySource mDependencySource;
public DataRepository() {
//1.实例化所依赖的Component。
DependencyComponent dependencyComponent = DaggerDependencyComponent.create();
//2.在构建时传入依赖的Component实例。
DaggerSourceComponent.builder().dependencyComponent(dependencyComponent).build().inject(this);
}
public String getDependencyData() {
return mDependencySource.getData();
}
}
2.3 小结
当通过这种依赖于其它Component方式完成注入时,Dagger2会去依赖的Component中查找它是否声明了 返回值为需要实例化的类的方法,如果有,那么就通过该Component来完成注入。
整个流程如下图所示:
依赖方式
对于被依赖的Component,它声明自己可以提供哪些类的实例化,但是并不知道具体有哪些Component需要依赖它。
三、使用继承方式完成注入
3.1 定义父 Component - SourceComponent
在第二节的例子中,我们让SourceComponent依赖于DependencyComponent,完成DependencySource的依赖注入。
下面,我们演示让SourceComponent被其他的Component继承,使得其他Component可以通过它来完成依赖注入,这里唯一的不同,就是该Component需要定义一个getSubSourceComponent()来返回子Component,关于SubSourceComponent在3.2中会进行介绍。
@Component(dependencies = DependencyComponent.class, modules = SourceModule.class)
public interface SourceComponent {
public void inject(DataRepository dataRepository);
//SubSourceComponent 为子 Component。
SubSourceComponent getSubSourceComponent();
}
@Module
public class SourceModule {
@Provides
LocalSource provideLocalSource() {
return new LocalSource();
}
}
public class LocalSource {
public String getLocalData() {
return "获取到本地数据";
}
}
3.2 定义子 Component - SubSourceComponent
下面,我们来定义SubSourceComponent,与之前的Component不同,在接口上,加上的是@SubComponent注解,并且不需要给它指定一个Module,因为它是通过父Component来实现实例化对象的。
@Subcomponent
public interface SubSourceComponent {
public void inject(SubRepository subRepository);
}
接下来,需要通过以下几步来完成依赖注入:
- 在需要注入的变量上加上
@Inject标签 - 点击
make,完成一次编译 - 首先实例化父
SourceComponent - 通过在
3.1中SourceComponent定义的getSubSourceComponent获取到SubSourceComponent实例。 - 调用
SubSourceComponent的inject方法完成注入。
public class SubRepository {
@Inject
LocalSource mLocalSource;
public SubRepository() {
//1.实例化所依赖的Component。
DependencyComponent dependencyComponent = DaggerDependencyComponent.create();
//2.在构建时传入依赖的Component实例。
SourceComponent sourceComponent = DaggerSourceComponent.builder().dependencyComponent(dependencyComponent).build();
//3.获取SubComponent。
SubSourceComponent subSourceComponent = sourceComponent.getSubSourceComponent();
//4.完成依赖注入。
subSourceComponent.inject(this);
}
public String getLocalData() {
return mLocalSource.getLocalData();
}
}
3.3 小结
通过继承方式来实现依赖注入时,父Component也就是SourceComponent需要声明一个getXXX方法,该方法返回子Component,这个子Component需要加上@SubComponent注解,它不用自己声明Module,而是通过与父Component关联的Module来完成依赖注入。
整个流程图如下所示:
继承方式
四、实例演示
下面,我们用一段小程序来演示上面的运行结果:
public class ComponentActivity extends AppCompatActivity {
private static final String TAG = ComponentActivity.class.getSimpleName();
private Button mBtnGetData;
private Button mBtnGetNetData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qualifier);
mBtnGetData = (Button) findViewById(R.id.bt_get_data);
mBtnGetData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DataRepository repository = new DataRepository();
String data = repository.getDependencyData();
Toast.makeText(ComponentActivity.this, data, Toast.LENGTH_SHORT).show();
}
});
mBtnGetNetData = (Button) findViewById(R.id.bt_get_net_data);
mBtnGetNetData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SubRepository repository = new SubRepository();
String data = repository.getLocalData();
Toast.makeText(ComponentActivity.this, data, Toast.LENGTH_SHORT).show();
}
});
}
}
更多文章,欢迎访问我的 Android 知识梳理系列:
- Android 知识梳理目录:http://www.jianshu.com/p/fd82d18994ce
- 个人主页:http://lizejun.cn
- 个人知识总结目录:http://lizejun.cn/categories/













网友评论