一、对有构造函数的依赖注入涉及到如下内容:
@Inject@Component@Inject和@Component协同作战。
二、问题背景
在介绍他们之前我们来看一段我们在项目中看到的类似的代码:
public class ClassA{
ClassB classB = new ClassB();
ClassC classC = new ClassC("xxx",xxx);
.....
}
当我们在目标类初始化其他类时,这些工作几乎都是重复性的操作,而且有强耦合性,所以需要一种方案来替代这种写法
三、依赖注入方案
@Inject
@Inject为了实现以上功能,我们需要完成以下步骤:
需要用注解 @Inject (Annotation) 来标注目标类中依赖类的实例对象
同样用注解 @Inject (Annotation) 来标注所依赖的其他类的 构造函数。
目标类 ClassA
public class ClassA{
@Inject
ClassB classB;// 使用 @Inject 标注依赖类的实例对象
@Inject
ClassC classC;
}
依赖类 ClassB
public class ClassB{
@Inject // 使用 @Inject 标注依赖类的构造函数
public ClassB(){}
....
}
依赖类 ClassC
public class ClassC{
@Inject
public ClassC(XXX xxx, XXX xxx){
...
}
}
注意:在使用 @Inject 标注类的构造函数,只能标注一个构造函数,无法标注多个。 虽然 目标类 和 依赖类 都使用了@Inject 来标记,但是他们并没有产生实在意义上的联系,这时 @Component 就充当了媒婆的角色。
@Component
作用:将 Module 中产生的依赖对象自动注入到需要依赖实例的 Container中
从上面的描述中我们可以看到 Component 充当了 Module 和 Container 的媒介。
很明显 @Component 是一个注解,那么被 @Component 标记的类理所当然的被称为 注解类,并且该类必须是接口或抽象类。那么下面我们看一下这个媒婆是怎么开展工作的:
- @Component 标注类的实例必须存在目标类中
- Component会查找目标类中用 @Inject 注解标注的属性
- 查找到相应的属性后,会接着查找该属性对应的用 @Inject 标注的构造函数(这时候就发生联系了)
- 剩下的工作就是初始化该属性的实例并把实例进行赋值
四、案例
public class User {
private String mName = "xing mo";
private int mAge = 18;
@Inject
public User() { }
public String getName() {
return mName;
}
public void setName(String mName) {
this.mName = mName;
}
public int getAge() {
return mAge;
}
public void setAge(int mAge) {
this.mAge = mAge;
}
}
@Component
public interface UserComponent {
void inject(MainActivity mMainActivity);
}
public class MainActivity extends AppCompatActivity {
@Inject
User mUser;
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
// 这一句代码是完成依赖注入的关键
DaggerUserComponent.builder().build().inject(this);
Log.e(TAG,"name : " + mUser.getName() + " age :" + mUser.getAge());
mUser.setAge(60);
mUser.setName("test");
Log.e(TAG,"name2 : " + mUser.getName() + " age2 :" + mUser.getAge());
}
}
注:DaggerUserComponent 是编译之后产生的,需要build之后导入即可