接上一篇Dagger2初探(一)继续讲Dagger2中的一些注解。
@Qualifier和@Named
关于这里有这么一个场景,有一个测试接口和一个线上接口,调用哪个接口一般通过一个标志位来区分, 上代码:
1 | public class QualifierActivity extends AppCompatActivity { |
ApiServerModule.java
1 |
|
NetModule.java
1 |
|
QualifierComponent.java
1 | (modules = {ApiServerModule.class, NetModule.class}) |
然后Make Project, 发现报错了
因为ApiServerModule里有两个方法的返回值都是ApiServer,Component一脸懵逼,愣是搞不懂把哪两个”绑定”起来,直接罢工了。所以这里需要用@Named注解来标注,从而区分这两个对象。
现在修改代码:
ApiServerModule.java
1 |
|
QualifierActivity.java
1 | public class QualifierActivity extends AppCompatActivity { |
打印结果:
1 | 05-17 10:19:27.307 13288-13288/me.mundane.dagger2learning D/NetModule: provideOkhttpClient |
可以看到成功注入了两个ApiServer对象
其实这里的@Named注解也只是@Qualifier中的一种而已,我们直接看@Named的源码
1 |
|
我们可以不使用@Named而使用@Qualifier来自定义两个注解。
Release.java
1 |
|
Test.java
1 |
|
使用这两个注解替换@Named(“test”)和@Named(“release”)
查看打印结果:
1 | 05-17 10:51:09.746 15573-15573/me.mundane.dagger2learning D/NetModule: provideOkhttpClient |
可以看到效果和@Named是一样的。
Provides, Lazy
还是直接上代码
Dog.java
1 | public class Dog { |
DogComponent.java
1 | (modules = DogModule.class) |
LazyActivity.java
1 | public class LazyActivity extends AppCompatActivity { |
打印结果:
1 | 05-17 11:48:31.858 19046-19046/me.mundane.dagger2learning D/DogModule: provideDog |
可以发现,和普通的@Inject不同,普通的@Inject是在注入后就开始创建对象了,而Lazy和Provider对象只有在调用get()方法的时候才会去调用Module里的provide方法。
区别在于:
Lazy是懒加载,以后每次调用get会得到同一个对象。
Provider不是懒加载,以后每次调用get会再强制调用对应module层的Provides方法一次,根据Provides方法具体实现不同。
@Binds
@Binds类似于@Provides, 区别是@Binds用于修饰抽象类中的抽象方法, 看一下使用实例吧。
Presenter接口和PresenterImpl
Presenter.java
1 | public interface Presenter { |
PresenterImpl.java
1 | public class PresenterImpl implements Presenter { |
PresenterModule是这里的关键,@Binds也是用在这里的
1 | // @Module may not contain both non-static @Provides methods |
注意到abstract。module类和这个bind方法都是抽象的。参数类型为PresenterImpl,意思就是说,想要注入Presenter, 请找PresenterImpl。
然后我们再写一个PresenterImplModule提供具体的Presenter实现类
1 |
|
BindsComponent.java
1 | (modules = {PresenterModule.class, PresenterImplModule.class}) |
BindsActivity.java
1 | public class BindsActivity extends AppCompatActivity { |
打印结果:
1 | 05-17 15:15:06.821 13285-13285/me.mundane.dagger2learning D/BindsActivity: mPresenterImpl = me.mundane.dagger2learning.bean.PresenterImpl@79efdd7 |
可以看到成功注入了一个Presenter的实现类的对象。
需要注意的地方:
@Provides和@Binds这两个不能共存于一个module。
@IntoSet
之前介绍的内容都是单个对象的注入,那么我们是否能将多个对象注入到容器中呢?首先是Set。
IntoSetModule.java
1 |
|
IntoSetComponent.java
1 | (modules = IntoSetModule.class) |
IntoSetActivity.java
1 | public class IntoSetActivity extends AppCompatActivity { |
打印结果:
1 | 05-17 17:05:42.247 18727-18727/me.mundane.dagger2learning D/Player: 1 is playing |
可以看到这个Set被成功注入了,并且里面包含了两个对象。
当然因为Set是无序的,所以在这个Set中play1在前面还是play2在前面也是不确定的。
进阶用法:
可以同时向 Set 注入多个对象。修改IntoSetModule.java
1 |
|
打印结果:
1 | 05-17 17:11:57.565 19836-19836/me.mundane.dagger2learning D/Player: 2 is playing |
当然也是无序的。
@IntoMap
@IntoMap其实和@IntoSet类似
IntoMapModule.java
1 |
|
IntoMapComponent.java
1 | (modules = IntoMapModule.class) |
IntoMapActivity.java
1 | public class IntoMapActivity extends AppCompatActivity { |
打印结果:
1 | 05-17 19:10:04.299 26236-26236/me.mundane.dagger2learning D/IntoMapActivity: mPlayers = {1=me.mundane.dagger2learning.bean.Player@2afd2a8, 2=me.mundane.dagger2learning.bean.Player@cfc11c1} |
可以看到也成功将多个对象注入到了Map容器当中
除了@StringKey以外,目前dagger2预定义的有:
- @ClassKey
- @IntKey
- @LongKey
@MapKey:
我们观察@StringKey的源码可以发现是这样的:
1 |
|
如果我们要使用@MapKey自定义一个@xxxKey的话,返回类型必须是以下几类:
- 基本数据类型
- String
- Class
- 枚举类型
- 注解类型
- 以上数据类型的数组
但是还可以指定 Enum 类型,或者特定的类的。
1 | enum MyEnum { |
还有个复合键值,但是就暂时写到这里吧。