一.在我们编程中可能回出现下面的情况
有一个类会在多个类中用到,这时我们想依赖注入,就会出现一个Module对象注入到多个调用者中的情况
这时候我们应该怎么做呢?
在这里我要说明一下Module 和桥梁
Component
是成对存在的
1.定义一个顶级的Module
这个module 提供了
Context
@Module
public
class
AppModule
{
private
Context mContext;
public
AppModule(Context context){ mContext = context; }
@Provides
Context providesContext(){
// 提供Context对象
return
mContext; }}
现在我们有两个或以上的调用者用到Context 对象
所以我们就要定义下层的多个module,获取到Context
2.
所以我们要将顶级Module 的Context 提供出去
//顶级Module 的桥梁@Component(modules = AppModule.class)public interface AppComponent {
// 向其下层提供Context 对象 Context proContext();}
3.下层Module获得 Context
// 下层Module类@Modulepublic class ActivityMoudule { @Provides Person providePerson(Context context){ // 此方法需要Context 对象
//上层传过来的Context 对象 return new Person(context); }}
4.下层Module 的桥梁提供给调用者
//下层Module 的桥梁@Component(dependencies = AppComponent.class,modules = ActivityMoudule.class)public interface ActivityComponent { // 注入 void inject(MainActivity activity);}
5.调用者被注入
// 顶级依赖对象 Component AppComponent appCom = DaggerAppComponent.builder().appModule(new AppModule(this)).build(); // 子类依赖对象 ,并注入 DaggerActivityComponent.builder() .appComponent(appCom) .activityMoudule(new ActivityMoudule()) .build() .inject(this);
二.@Qualifier 自定义标记
在使用中,会出现两个方法返回对象相同时的情况,那么如何区分呢。
@Qualifier
:当类的类型不足以鉴别一个依赖的时候,我们就可以使用这个注解标示。例如:在Android中,我们会需要不同类型的context,所以我们就可以定义 qualifier注解“@perApp”和“@perActivity”,这样当注入一个context的时候,我们就可以告诉 Dagger我们想要哪种类型的context。
我的理解就是,当要注入的对象的类型不能确定是唯一的,这时就要自定义注解用来标记注入的具体是那个类
例:参数是Content ,我们可以传入Activity或者Application 这样我们就定义两个注解标记
举个栗子:
bean类Person 中有两个构造器 通过传入不同的参数来实例化对象
public class Person { private Context mContext; public Person(Context context){ mContext = context; Log.i("dagger","create"); } public Person(String name){ Log.i("dagger",name); }}
这种情况注入依赖:
第一种方式:这种方式和Qualifier无关
ActivityModule
中添加
@Named
标记
@Module
public
class
ActivityMoudule
{
@Named
(
"Context"
)
// 通过context创建Person 对象
@Provides
Person providePersonContext(Context context){
// 此方法需要Context 对象
return
new
Person(context); }
@Named
(
"name"
)
// 通过name创建Person 对象
@Provides
Person providePersonName(){
// 此方法需要name
return
new
Person(
"1234"
); }}
使用时,也需要添加此标记
public
class
MainActivity
extends
AppCompatActivity
{
@Named
(
"context"
)
// 标记
@Inject
Person person;
@Named
(
"name"
)
// 标记
@Inject
Person person2;
@Override
protected
void
onCreate(@Nullable Bundle savedInstanceState) {
super
.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
//注入
component.inject(
this
);*/
// 依赖对象 Component
AppComponent appCom = DaggerAppComponent.builder().appModule(
new
AppModule(
this
)).build();
// 子类依赖对象 ,并注入
DaggerActivityComponent.builder() .appComponent(appCom) .activityMoudule(
new
ActivityMoudule()) .build() .inject(
this
); } }
使用时,使用者的
@Inject
上,必须要加入注解
@Named("xxx")
,不然编译期会报错。
这样使用过程中,虽然解决了问题,但是通过字符串标记一个对象,容易导致前后不匹配,
第二种方式:自定义注解(
@Qualifier
)
自定义两个注解,分别对应
Context
和
name
。
@Qualifier
// 关键词
@Retention
(RetentionPolicy.RUNTIME)
// 运行时仍可用
public
@
interface
PersonForContext
{
// Context 对象的注解
}
@Qualifier
@Retention
(RetentionPolicy.RUNTIME)
public
@
interface
PersonForName
{
// name 对象的注解
}
在使用
@Named("")
的地方替换为自定义的注解
@PersonForContext
// 通过context创建Person 对象
@Provides
Person providePersonContext(Context context){
// 此方法需要Context 对象
return
new
Person(context); }
@PersonForName
// 通过name创建Person 对象
@Provides
Person providePersonName(){
// 此方法需要Context 对象
return
new
Person(
"123"
); }
注入时:
@PersonForContext
// 标记
@Inject
Person person;
@PersonForName
// 标记
@Inject
Person person2;