继续学习在代码中会看到的标注:@Named、@Qualifier、@Singleton、@Scope。这四个标注包括以前学的@Inject其实不是在dagger的包中,而是javax-inject包中:java
通过上篇的学习,结合@Inject、@Component、@Module、@Provides的使用,先看一个例子:android
City.javagit
public class City {
private String name;
public City() {}
public String show() {
return name;
}
public void setName(String name) {
this.name = name;
}
}复制代码
BeanModule.javagithub
@Module
public class BeanModule {
@Provides
City providerCityCD() {
City city = new City();
city.setName("成都");
return city;
}
@Provides
City providerCityZG(){
City city = new City();
city.setName("自贡");
return city;
}
}复制代码
MainActivityComponent.java缓存
@Component(modules = BeanModule.class)
public interface MainActivityComponent {
void inject(MainActivity activity);
}复制代码
MainActivity.javabash
public class MainActivity extends AppCompatActivity {
public static String TAG = "hcy";
@Inject
City city;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//in Android Studio, select Build > Rebuild Project
DaggerMainActivityComponent.create().inject(this);
Log.d(TAG, "city name: " + city.show());
}
}复制代码
一跑起来就GG了ide
心路历程是这样的,MainActivity.java做为依赖需求方,编译生成MainActivity_MembersInjector,BeanModule.java做为依赖提供方,编译生成两个Xx_Factory,那么问题来了,有两个“备胎”供选择,你选谁?Component一脸懵逼,愣是搞不懂把哪两个"绑定"起来,直接罢工了,所以能够看到上篇中的DaggerMainActivityComponent在这里没有生成。函数
那么告诉Component咱们要的是哪一个不就行啦?可使用@Named标注,改下BeanModule.java学习
@Module
public class BeanModule {
@Named("CD")
@Provides
City providerCityCD() {
City city = new City();
city.setName("成都");
return city;
}
@Named("ZG")
@Provides
City providerCityZG() {
City city = new City();
city.setName("自贡");
return city;
}
}复制代码
MainActivity.javaui
public class MainActivity extends AppCompatActivity {
public static String TAG = "hcy";
@Named("CD")
@Inject
City city;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//in Android Studio, select Build > Rebuild Project
DaggerMainActivityComponent.create().inject(this);
Log.d(TAG, "city name: " + city.show());复制代码
@Named("参数")和被引用的地方填的一致就能够了,编译运行就不会报错了。此时编译生成的文件:
熟悉的DaggerMainActivityComponent又回来了,并且两个依赖提供者也都在,经过打印咱们知道选的是CD,那它是怎么实现的呢?看下DaggerMainActivityComponent的initialize():
private void initialize(final Builder builder) {
this.providerCityCDProvider = BeanModule_ProviderCityCDFactory.create(builder.beanModule);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create(providerCityCDProvider);
}复制代码
能够看到,依赖提供方和需求方经过@Named加了相同的标注CD后,在建立工厂的时候只会把CD这个提供方初始化,ZG根本没有露脸的机会,后面的流程就跟上篇同样了。
使用@Qualifier能够实现@Named同样的功能,Qualifier翻译过来是修饰符的意思,先看下用法,再分析@Qualifier和@Named之间的“苟且”。添加一个接口CD.java和ZG.java
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface CD {}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface ZG {}复制代码
修改BeanModule.java以下:
@Module
public class BeanModule {
@CD
@Provides
City providerCityCD() {
City city = new City();
city.setName("成都");
return city;
}
@ZG
@Provides
City providerCityZG() {
City city = new City();
city.setName("自贡");
return city;
}
}复制代码
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static String TAG = "hcy";
@CD
@Inject
City city;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//in Android Studio, select Build > Rebuild Project
DaggerMainActivityComponent.create().inject(this);
Log.d(TAG, "city name: " + city.show());
}
}复制代码
修改后和输出结果、编译生成的类以及源码都和@Named一毛同样。@Qualifier可让咱们本身建立限定符,其实@Named内部也是经过@Qualifier实现,源码以下:
/**
* String-based {@linkplain Qualifier qualifier}.
*
* <p>Example usage:
*
* <pre>
* public class Car {
* @Inject <b>@Named("driver")</b> Seat driverSeat;
* @Inject <b>@Named("passenger")</b> Seat passengerSeat;
* ...
* }</pre>
*/
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
/** The name. */
String value() default "";
}复制代码
从注释可知@Named是@Qualifier的String型实现;看下github上一张介绍图:
顺便提一下这里的@Retention,翻译过来是保留的意思,它是用来指定咱们自定义的限定符能保留的多久,有三种可选:
/**
* Indicates how long annotations with the annotated type are to
* be retained. If no Retention annotation is present on
* an annotation type declaration, the retention policy defaults to
* {@code RetentionPolicy.CLASS}.
*/
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}复制代码
@Singleton从名字就知道是单例,怎么用这个?先看一个例子:
City.java
public class City {
public City() {}
}复制代码
BeanModule.java
@Module
public class BeanModule {
@Named("CD")
@Provides
City providerCityCD() {
City city = new City();
return city;
}
@Named("ZG")
@Provides
City providerCityZG() {
City city = new City();
return city;
}
}复制代码
MainActivityComponent.java
@Component(modules = BeanModule.class)
public interface MainActivityComponent {
void inject(MainActivity activity);
}复制代码
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static String TAG = "hcy";
@Named("CD")
@Inject
City cityCD1;
@Named("CD")
@Inject
City cityCD2;
@Named("ZG")
@Inject
City cityZG1;
@Named("ZG")
@Inject
City cityZG2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//in Android Studio, select Build > Rebuild Project
DaggerMainActivityComponent.create().inject(this);
Log.d(TAG, "cityCD1 is: " + cityCD1);
Log.d(TAG, "cityCD2 is: " + cityCD2);
Log.d(TAG, "cityZG1 is: " + cityZG1);
Log.d(TAG, "cityZG2 is: " + cityZG2);
}
}复制代码
例子很简单,打印city以下:
D/hcy (13129): cityCD1 is: com.hcy.huchengyang.dagger2.bean.City@35051924
D/hcy (13129): cityCD2 is: com.hcy.huchengyang.dagger2.bean.City@36acdc8d
D/hcy (13129): cityZG1 is: com.hcy.huchengyang.dagger2.bean.City@14db0e42
D/hcy (13129): cityZG2 is: com.hcy.huchengyang.dagger2.bean.City@28a95e53复制代码
能够看到这里获取到的对应4个不一样的city,按照上一篇的分析套路能够很快定位到缘由,查看编译生成的MainActivity_MembersInjector.java中的injectMembers()方法
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.cityCD1 = cityCD1AndCityCD2Provider.get();
instance.cityCD2 = cityCD1AndCityCD2Provider.get();
instance.cityZG1 = cityZG1AndCityZG2Provider.get();
instance.cityZG2 = cityZG1AndCityZG2Provider.get();
}复制代码
这里会调用目标工厂的get方法,最后调用到BeanModule的方法建立对象;若是要确保单例,@Singleton就能够派上用场了。
1.在提供依赖的构造函数上加@Singleton
@Module
public class BeanModule {
@Named("CD")
@Provides
@Singleton
City providerCityCD() {
City city = new City();
return city;
}
@Named("ZG")
@Provides
City providerCityZG() {
City city = new City();
return city;
}
}复制代码
2.@Component标注的接口加上@Singleton
@Singleton
@Component(modules = BeanModule.class)
public interface MainActivityComponent {
void inject(MainActivity activity);
}复制代码
修改后打印:
D/hcy (13519): cityCD1 is: com.hcy.huchengyang.dagger2.bean.City@35051924
D/hcy (13519): cityCD2 is: com.hcy.huchengyang.dagger2.bean.City@35051924
D/hcy (13519): cityZG1 is: com.hcy.huchengyang.dagger2.bean.City@36acdc8d
D/hcy (13519): cityZG2 is: com.hcy.huchengyang.dagger2.bean.City@14db0e42复制代码
那么它是怎么保证单例的呢?查看源码会发现MainActivity_MembersInjector.java中的injectMembers()方法和以前是同样的,可是DaggerMainActivityComponent.java的initialize()方法发生了改变:
private void initialize(final Builder builder) {
this.providerCityCDProvider =
DoubleCheck.provider(BeanModule_ProviderCityCDFactory.create(builder.beanModule));
this.providerCityZGProvider = BeanModule_ProviderCityZGFactory.create(builder.beanModule);
this.mainActivityMembersInjector =
MainActivity_MembersInjector.create(providerCityCDProvider, providerCityZGProvider);
}复制代码
这里多了DoubleCheck的操做。看下DoubleCheck.java
public final class DoubleCheck<T> implements Provider<T>, Lazy<T> {
private static final Object UNINITIALIZED = new Object();
private volatile Provider<T> provider;
private volatile Object instance = UNINITIALIZED;
private DoubleCheck(Provider<T> provider) {
assert provider != null;
this.provider = provider;
}
@Override
public T get() {
Object result = instance;
if (result == UNINITIALIZED) {//第一次取值后下次再来判断不知足直接返回以前的实例
synchronized (this) {
result = instance;
if (result == UNINITIALIZED) {
result = provider.get();
Object currentInstance = instance;
if (currentInstance != UNINITIALIZED && currentInstance != result) {
throw new IllegalStateException();
}
instance = result;
provider = null;
}
}
}
return (T) result;
}
public static <T> Provider<T> provider(Provider<T> delegate) {
checkNotNull(delegate);
if (delegate instanceof DoubleCheck) {
return delegate;
}
return new DoubleCheck<T>(delegate);
}
}复制代码
整个类都没多少代码,省略了注释和异常以及部分代码,DoubleCheck和咱们的Factory都实现了共有接口Provider,保证单例的操做就是这里的get()方法,注释已解释,能够跟着流程走一波。这里看下github上的一张图,下图左边的对应没有标注@Singleton,每次取时都会从新new;右边有标注的在第一次建立时会缓存一份,下次再获取直接就返回缓存的。
使用@Scope能够实现@Singleton同样的功能,Scope翻译过来是做用域的意思,其实@Singleton就是@Scope的实现(有点像上面@Named和@Qualifier的关系),源码以下:
@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}复制代码
咱们能够彻底能够本身定义一个接口如:MainActivityScope.java
@Scope
@Documented
@Retention(value= RetentionPolicy.RUNTIME)
public @interface MainActivityScope{}复制代码
修改MainActivityComponent.java
@MainActivityScope
@Component(modules = BeanModule.class)
public interface MainActivityComponent {
void inject(MainActivity activity);
}复制代码
修改BeanModule.java
@Module
public class BeanModule {
@Named("CD")
@Provides
@MainActivityScope
City providerCityCD() {
City city = new City();
return city;
}
@Named("ZG")
@Provides
City providerCityZG() {
City city = new City();
return city;
}
}复制代码
效果是同样的,@Scope是成对使用的,在@Module的@Provides方法上使用@Scope标注,那么对应的@Component也须要@Scope标准,此时@Provides方法提供的依赖在@Component中为单例。
未完待续...