Dagger2 系列文章
Dagger2 知识梳理(1) - Dagger2 依赖注入的两种方式
Dagger2 知识梳理(2) - @Qulifier 和 @Named 解决依赖注入迷失
Dagger2 知识梳理(3) - 使用 dependencies 和 @SubComponent 完成依赖注入
Dagger2 知识梳理(4) - @Scope 注解的使用
一、前言
在 Dagger2 知识梳理(1) - Dagger2 依赖注入的两种方式 中,我们介绍了两种依赖注入的方式,其中第二种是通过给注入器Component
指定Module
,再由Module
提供创建实例的方法,来实现依赖注入,这是一种“自给自足”的方式,在这种情况下,我们的Component
是这么声明的:
除此之外,还有另外两种方式,让
Component
可以通过其他的
Component
完成依赖注入,可以划分为:
依赖方式 和
继承方式。
- 通过依赖方式实现时,需要在
Component
中指定它所依赖的Component
名字:
而被依赖的Component
需要声明它可以提供哪些类的实例化,因此它需要在Component
中声明一些返回值为这些类的方法:
- 通过继承方式时实现时,子
Component
类需要用@SubComponent
声明,这种情况下,它一般类似于下面这样:
并且我们不能直接创建该Component
的实例来完成依赖注入,而是需要由父Component
实例提供一个getXXX
来将这个SubComponent
返回给使用者,SubComponent
自动拥有了父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/