Code example
// 父类
abstract class Animal {
// 抽象方法
abstract void sleep();
}
// 子类
class Tiger extends Animal {
@Override
public void sleep() {
System.out.println("Tiger sleeping");
}
}
// 子类
class Cat extends Animal {
@Override
public void sleep() {
System.out.println("Cat sleeping");
}
}
@Module
class ZooModule {
@Singleton // Tiger对象保证单例
@Provides
@IntoSet // 将Tiger对象存入Set集合中
public Animal providerTiger() {
return new Tiger();
}
@Singleton // Cat对象保证单例
@Provides
@IntoSet // 将Cat对象存入Set集合中
public Animal providerCat() {
return new Cat();
}
}
@Singleton // 保证ZooModule中的对象单例
@Component(modules = {
ZooModule.class})
interface ZooComponent {
void inject(Zoo zoo);
}
public class Zoo {
@Inject
Set<Animal> set0;
@Inject
Set<Animal> set1;
@Test
public void 案例十一() {
DaggerZooComponent.create().inject(this);
set0.forEach(new Consumer<Animal>() {
@Override
public void accept(Animal animal) {
animal.sleep();
}
});
set1.forEach(new Consumer<Animal>() {
@Override
public void accept(Animal animal) {
animal.sleep();
}
});
}
}
Dagger2 generated code reading
Mainly analyze how to generate a Set collection
Looking at the code generated by Degger2 based on the above case, the generated code is in the build\generated\sources\annotationProcessor\..
folder.
- Analyzing the injected logic, you can basically figure it out.
.inject(this)
The logic after calling the injection is as follows:
final class DaggerZooComponent implements ZooComponent {
@Override
public void inject(Zoo zoo) {
injectZoo(zoo);
}
private Zoo injectZoo(Zoo instance) {
// getSetOfAnimal()该方法注意
Zoo_MembersInjector.injectSet0(instance, getSetOfAnimal());
Zoo_MembersInjector.injectSet1(instance, getSetOfAnimal());
return instance;
}
private Set<Animal> getSetOfAnimal() {
// providerTigerProvider.get() 保证Tiger对象单例
// providerCatProvider.get() 保证Cat对象单例
// 前面有分析过
// 主要看SetBuilder.<Animal>newSetBuilder(2).add().build()
return SetBuilder.<Animal>newSetBuilder(2).add(providerTigerProvider.get()).add(providerCatProvider.get()).build();
}
}
- Analyze how to create a
Set<Animal>
collection and add elements
public final class SetBuilder<T> {
// SetBuilder.<Animal>newSetBuilder(2)
// 创建一个SetBuilder对象,estimatedSize代表集合长度
public static <T> SetBuilder<T> newSetBuilder(int estimatedSize) {
return new SetBuilder<T>(estimatedSize);
}
// SetBuilder构造方法
private SetBuilder(int estimatedSize) {
// 它创建了一个List集合
contributions = new ArrayList<>(estimatedSize);
}
// .add(providerTigerProvider.get())
// 该方法将获取到的单例对象存入List集合中.
public SetBuilder<T> add(T t) {
contributions.add(checkNotNull(t, SET_CONTRIBUTIONS_CANNOT_BE_NULL));
return this;
}
// .build()
// 最后一步是将list集合中的元素转化为Set集合,到这里就弄清楚@IntoSet注解所做的事情了.
public Set<T> build() {
switch (contributions.size()) {
case 0:
return Collections.emptySet();
case 1:
return Collections.singleton(contributions.get(0));
default:
return Collections.unmodifiableSet(new HashSet<>(contributions));
}
}
}
In addition, in the case code, @Singleton
annotations can only guarantee that the elements Zoo
in different Set<Animal>
collection objects are the same, but cannot guarantee that the Set<Animal>
objects are singletons.
@Binds
Annotation usage
@Binds
Annotation is used to replace@Provides
annotations.In the above case code, annotations are used to@Provides
provide objects for the syringe. Here's how to use@Binds
annotations.
abstract class Animal {
abstract void sleep();
}
class Tiger extends Animal {
// 这里需要在构造上增加@Inject注解,
// 因为Module中没有使用@Provides注解,用户没有手动提供Tiger对象,
// 此时就需要Dagger2来创建Tiger对象,现实中也可以使用其他的Module来提供对象也行.
@Inject
public Tiger() {
}
@Override
public void sleep() {
System.out.println("Tiger sleeping");
}
}
class Cat extends Animal {
@Inject
public Cat() {
}
@Override
public void sleep() {
System.out.println("Cat sleeping");
}
}
//
@Module
abstract class ZooModule {
@Singleton //该注解有效,依旧能保证Tiger对象在注射器证明周期中为单例.
@IntoSet
// 近似看作@Provides注解
@Binds
// 方法需要是抽象方法,providerTiger方法的入参必须是Animal接口或者抽象类的实现类类型.
abstract Animal providerTiger(Tiger tiger);
@Singleton //该注解有效,依旧能保证Cat对象在注射器证明周期中为单例.
@IntoSet
@Binds
abstract Animal providerCat(Cat cat);
}
@Singleton
@Component(modules = {
ZooModule.class})
interface ZooComponent {
void inject(Zoo zoo);
}
public class Zoo {
@Inject
Set<Animal> set0;
@Inject
Set<Animal> set1;
@Test
public void 案例十一() {
DaggerZooComponent.create().inject(this);
set0.forEach(new Consumer<Animal>() {
@Override
public void accept(Animal animal) {
animal.sleep();
}
});
set1.forEach(new Consumer<Animal>() {
@Override
public void accept(Animal animal) {
animal.sleep();
}
});
}
}
@Binds
@Provides
There are still many subtle differences between annotations and annotations, and I think it will be more flexible to use with @Binds
annotations Dagger2
.