史上最适合新手的Dagger2教程(二)对象注入
Dagger2系列教程目录:
史上最适合新手的Dagger2教程(五)命名、限定与延时加载
0.检查作业
对答案了对答案了,后面那排睡觉的,起来做笔记了!
杠精类:
public class GangJing {
@Inject
public GangJing() {
}
public void gang(Activity activity) {
Toast.makeText(activity, "这抠脚大汉天天卖萌", Toast.LENGTH_SHORT).show();
}
}
注入器:
注入器和上节课写的是一样的,不需要修改~
@Component
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
}
注入和调用:
public class MainActivity extends AppCompatActivity {
@Inject
GangJing gangJing;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivityComponent.create().inject(this);
gangJing.gang(this);
}
}
那么这节课我们基于上节课的作业继续讲解Dagger2.
· 对象注入
有时候我们的项目,需要创建A和B两个对象,其中B对象需要用到A的实例,如:
A a = new A();
B b = new B(a);
这个时候,我们就要用到Dagger2的对象注入了。
我们把上节课的卖萌类拿过来:
public class SellMoe {
@Inject
public SellMoe() {
}
public String sellMoe() {
return "赶紧卖了个大萌";
}
}
然后改造一下作业里的杠精类:
在内部声明一个卖萌类对象,在构造方法中传入它;
然后添加一个方法看它卖萌(lookAtHim),调用卖萌类的方法。
public class GangJing {
//新增一个卖萌对象
SellMoe sellMoe;
//修改构造方法,传入卖萌对象
public GangJing(SellMoe sellMoe) {
this.sellMoe = sellMoe;
}
//添加一个调用卖萌对象的方法
public String lookAtHim() {
return sellMoe.sellMoe();
}
public void gang(Activity activity) {
Toast.makeText(activity, "这抠脚大汉天天卖萌", Toast.LENGTH_SHORT).show();
}
}
先不使用Dagger2:
public class MainActivity extends AppCompatActivity {
SellMoe sellMoe;
GangJing gangJing;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = findViewById(R.id.tv);
//关键代码
sellMoe = new SellMoe();
gangJing = new GangJing(sellMoe);
tv.setText(gangJing.lookAtHim());
gangJing.gang(this);
}
}
运行一下:
要把SellMoe注入到GangJing里面去,只要在传入SellMoe的构造方法上加上@Inject就好:
public class GangJing {
SellMoe sellMoe;
@Inject
public GangJing(SellMoe sellMoe) {
this.sellMoe = sellMoe;
}
public String lookAtHim() {
return sellMoe.sellMoe();
}
public void gang(Activity activity) {
Toast.makeText(activity, "这抠脚大汉天天卖萌", Toast.LENGTH_SHORT).show();
}
}
Step2:注入对象
注入器(@Component)依然使用作业里的注入器,无需修改~
直接在MainActivity里调用就OK:
public class MainActivity extends AppCompatActivity {
//注意这里没有声明SellMoe对象!
@Inject
GangJing gangJing;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注入对象
DaggerMainActivityComponent.create().inject(this);
TextView tv = findViewById(R.id.tv);
tv.setText(gangJing.lookAtHim());
gangJing.gang(this);
}
}
注意这里没有声明SellMoe对象,但是运行一下,发现并没有爆出空指针异常,
这说明Dagger2已经自动帮我们把SellMoe给注入到了GangJing类里了,厉害吧~
这就是Dagger2厉害到不行的智能对象注入,它在你用@Inject标记GangJing的构造方法的时候,就已经帮你创建好SellMoe对象了:
@Inject
public GangJing(SellMoe sellMoe) {
this.sellMoe = sellMoe;
}
基于此功能,使用Dagger2开发的项目,在构造方法被修改时无需修改调用处的代码,而且可以避免几乎所有的空指针!
有点开始懵逼了?那我用类比的方式说明一下:
@Inject
Object obj;
这个代码,相当于:
Object obj = new Object();
而这个代码:
ObjectA objA;
@Inject
public ObjectB(ObjectA objA){
this.objA = objA;
}
则相当于:
ObjectA objA;
public ObjectB(ObjectA objA){
this.objA = new ObjectA();
}
把@Inject注解理解成new操作,是不是就好理解了~
2.注意事项
值得一提的是,Dagger2在@Inject注入的时候,每次都会new一个对象。
比如我们给SellMoe加上一个字段id:
public class SellMoe {
public int id;
@Inject
public SellMoe() {
}
public String sellMoe() {
return "赶紧卖了个大萌";
}
}
在调用lookAtHim的时候打印一下id:
public String lookAtHim() {
Log.e("GangJingSellMoeID", sellMoe.id + "");
return sellMoe.sellMoe();
}
在MainActivity中同样注入一个SellMoe对象,给它的id赋值为1:
public class MainActivity extends AppCompatActivity {
@Inject
SellMoe sellMoe;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerMainActivityComponent.create().inject(this);
sellMoe.id = 1;
Log.e("MainSellMoeID", sellMoe.id + "");
再执行一次代码:
看到了吗,他们是两个不一样的卖萌类~
那么如果需要用到单例怎么办呢?