@BindsOptionalOf
分两种情况来看,我们在module中最终没有@Provides来提供对象。和最普通的情况其实很接近,MembersInjector构造函数中需要一个Provider<Optional<TestClass1>> 的对象,用来最终注入。
而这个对象在DaggerXXXComponent中提供
this.optionalOfTestClass1Provider = absentGuavaOptionalProvider();
private static <T> Provider<Optional<T>> absentGuavaOptionalProvider() {
@SuppressWarnings("unchecked") // safe covariant cast
Provider<Optional<T>> provider = (Provider<Optional<T>>) ABSENT_GUAVA_OPTIONAL_PROVIDER;
return provider;
}
其实就是将参数类型转换一下,看一下这个参数的生成
private static final Provider ABSENT_GUAVA_OPTIONAL_PROVIDER = InstanceFactory.create(Optional.absent());
它是一个static final类型的变量,如果你跟随里面的内容,你回发现,它其实就是产生一个空的Optinal<Object>,然后把它包装成一个InstanceFactory(继承与Factory->Provider)。
所以注入的时候通过InstanceFactory.get获取这个空的Optional<Object>,于是空流程结束了。
如果我们使用@Provides提供了TestClass1呢?
DaggerXXXComponent就改变了
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.getTestClass1Provider = NameModule_GetTestClass1Factory.create(builder.nameModule);
this.optionalOfTestClass1Provider =
PresentGuavaOptionalInstanceProvider.of(getTestClass1Provider);
this.personMembersInjector =
Person_MembersInjector.create(
optionalOfTestClass1Provider);
}
@Override
public Person inject(Person person) {
personMembersInjector.injectMembers(person);
return person;
}
public static final class Builder {
private NameModule nameModule;
private Builder() {}
public PersonComponent build() {
if (nameModule == null) {
this.nameModule = new NameModule();
}
return new DaggerPersonComponent(this);
}
public Builder nameModule(NameModule nameModule) {
this.nameModule = Preconditions.checkNotNull(nameModule);
return this;
}
}
/** A {@code Provider<Optional<T>>} that uses a delegate {@code Provider<T>}. */
private static final class PresentGuavaOptionalInstanceProvider<T>
implements Provider<Optional<T>> {
private final Provider<T> delegate;
private PresentGuavaOptionalInstanceProvider(Provider<T> delegate) {
this.delegate = Preconditions.checkNotNull(delegate);
}
@Override
public Optional<T> get() {
return Optional.of(delegate.get());
}
private static <T> Provider<Optional<T>> of(Provider<T> delegate) {
return new PresentGuavaOptionalInstanceProvider<T>(delegate);
}
}
initialize中,首先生成了ClassTest1 的 Provider(最基础的,研习一种有述)。然后使用PresentGuavaOptionalInstanceProvider进行封装继承于Provider<Optinal<T>> 对象。
封装很简单当调用get的时候,返回一个Optinal<T>即可。
以上关于BindsOptionalOf的实现就完成了。
@BindsInstance
关于@BindsInstance的使用对应的《Dagger2 使用(二)》介绍了很多,存在几种变种。关于@Qualifier在前篇我们已经提到过了,这里的应用原理是相同的。
所以还是来看下DaggerGameComponent
public final class DaggerGameComponent implements GameComponent {
...........
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.gameModeNameProvider = InstanceFactory.create(builder.gameModeName);
this.playerNameProvider = InstanceFactory.create(builder.playerName);
this.gameModeProvider = GameMode_Factory.create(gameModeNameProvider, playerNameProvider);
}
@Override
public GameMode getGameMode() {
return new GameMode(gameModeNameProvider.get(), playerNameProvider.get());
}
private static final class Builder implements GameComponent.Builder {
private String gameModeName;
private String playerName;
@Override
public GameComponent build() {
if (gameModeName == null) {
throw new IllegalStateException(String.class.getCanonicalName() + " must be set");
}
if (playerName == null) {
throw new IllegalStateException(String.class.getCanonicalName() + " must be set");
}
return new DaggerGameComponent(this);
}
@Override
public Builder gameModeName(String str) {
this.gameModeName = Preconditions.checkNotNull(str);
return this;
}
@Override
public Builder playerName(String str2) {
this.playerName = Preconditions.checkNotNull(str2);
return this;
}
}
}
Builder中多了两个我们定义的方法,并且将参数保存起来,没问题。区别还是在于initialize方法中,我们使用保存在Builder中的变量构建了InstanceFactory类型的值。这个类其实就是将参数封装成Factory而已,没什么特殊的(Factory继承与Provider)。
Set注入
首选,被注入的对象生成的MemberInjector其实并没有什么特殊,请求注入Set<Player>,所以MemberInjector需要一个Provider<Set<Player>>作为构造函数的参数。
所以问题还是集中在DaggerXXXComponent的initialize方法中(MemberInjector是在该方法中生成的。)
先看注入一个对象的情况
private void initialize(final Builder builder) {
this.getPlayer1Provider = GameModule_GetPlayer1Factory.create(builder.gameModule);
this.setOfPlayerProvider =
SetFactory.<Player>builder(1, 0).addProvider(getPlayer1Provider).build();
this.gameMembersInjector = Game_MembersInjector.create(setOfPlayerProvider);
}
GameModule_XXX是GameModule根据@Provides方法自动生成的类,之前已经介绍了。相比普通注入,注入到set多了一步,就是生成了一个SetFactory,并把GameModule_XXX添加进去。
关于这个SetFactory,我们等其他情况都介绍完了再来介绍,现在只需要知道他是一个Factory<Set<T>>类型的对象,当MembersInjector调用inject时能够正确get到Set<T>就行。
当注入多个对象的情况
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.getPlayer1Provider = GameModule_GetPlayer1Factory.create(builder.gameModule);
this.getPlayer2Provider = GameModule_GetPlayer2Factory.create(builder.gameModule);
this.setOfPlayerProvider =
SetFactory.<Player>builder(2, 0)
.addProvider(getPlayer1Provider)
.addProvider(getPlayer2Provider)
.build();
this.gameMembersInjector = Game_MembersInjector.create(setOfPlayerProvider);
}
SetFactory的构造有所改变,前面的1变成了2。推测,第一个参数表示注入多少个对象。
当使用@ElementsIntoSet之后
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.getPlayer1Provider = GameModule_GetPlayer1Factory.create(builder.gameModule);
this.getPlayer2Provider = GameModule_GetPlayer2Factory.create(builder.gameModule);
this.getPlayersProvider = GameModule_GetPlayersFactory.create(builder.gameModule);
this.setOfPlayerProvider =
SetFactory.<Player>builder(2, 1)
.addProvider(getPlayer1Provider)
.addProvider(getPlayer2Provider)
.addCollectionProvider(getPlayersProvider)
.build();
this.gameMembersInjector = Game_MembersInjector.create(setOfPlayerProvider);
}
三种情况的唯一不同点在于SetFactory的构造。所以我们来看下SetFactory类
public final class SetFactory<T> implements Factory<Set<T>> {
......
public static <T> Builder<T> builder(int individualProviderSize, int collectionProviderSize) {
return new Builder<T>(individualProviderSize, collectionProviderSize);
}
public static final class Builder<T> {
private final List<Provider<T>> individualProviders;
private final List<Provider<Collection<T>>> collectionProviders;
private Builder(int individualProviderSize, int collectionProviderSize) {
individualProviders = presizedList(individualProviderSize);
collectionProviders = presizedList(collectionProviderSize);
}
@SuppressWarnings("unchecked")
public Builder<T> addProvider(Provider<? extends T> individualProvider) {
assert individualProvider != null : "Codegen error? Null provider";
// TODO(ronshapiro): Store a List<? extends Provider<T>> and avoid the cast to Provider<T>
individualProviders.add((Provider<T>) individualProvider);
return this;
}
@SuppressWarnings("unchecked")
public Builder<T> addCollectionProvider(
Provider<? extends Collection<? extends T>> collectionProvider) {
assert collectionProvider != null : "Codegen error? Null provider";
collectionProviders.add((Provider<Collection<T>>) collectionProvider);
return this;
}
.......
}
private final List<Provider<T>> individualProviders;
private final List<Provider<Collection<T>>> collectionProviders;
......
@Override
public Set<T> get() {
int size = individualProviders.size();
// Profiling revealed that this method was a CPU-consuming hotspot in some applications, so
// these loops were changed to use c-style for. Versus enhanced for-each loops, C-style for is
// faster for ArrayLists, at least through Java 8.
List<Collection<T>> providedCollections =
new ArrayList<Collection<T>>(collectionProviders.size());
for (int i = 0, c = collectionProviders.size(); i < c; i++) {
Collection<T> providedCollection = collectionProviders.get(i).get();
size += providedCollection.size();
providedCollections.add(providedCollection);
}
Set<T> providedValues = newHashSetWithExpectedSize(size);
for (int i = 0, c = individualProviders.size(); i < c; i++) {
providedValues.add(checkNotNull(individualProviders.get(i).get()));
}
for (int i = 0, c = providedCollections.size(); i < c; i++) {
for (T element : providedCollections.get(i)) {
providedValues.add(checkNotNull(element));
}
}
return unmodifiableSet(providedValues);
}
}
代码选取了这里会用到的部分。其中presizedList方法其实就是创建一个指定大小的ArrayList。
所以 SetFactory.<Player>builder(2, 1) 方法中第一个参数表示 注入的Provider<T> 的数量,第二个参数表示注入的Provider<Set<T>> 的数量。
最主要的还是get方法,它主要作用是组织我在module中返回不同类型的Set<T>(HashSet 和 ArraySet),以及单个对象,将他们组合起来生成一个Set。有趣的是他返回的竟然是一个UnmodifuableSet!!
Map注入
几乎和Set注入一样的,我们直接看initialize方法
private Provider<Map<String, Provider<Player>>> mapOfStringAndProviderOfPlayerProvider;
private Provider<Map<String, Player>> mapOfStringAndPlayerProvider;
private void initialize(final Builder builder) {
this.getPlayer1Provider = GameModule_GetPlayer1Factory.create(builder.gameModule);
this.getPlayer2Provider = GameModule_GetPlayer2Factory.create(builder.gameModule);
this.mapOfStringAndProviderOfPlayerProvider =
MapProviderFactory.<String, Player>builder(2)
.put("1", getPlayer1Provider)
.put("2", getPlayer2Provider)
.build();
this.mapOfStringAndPlayerProvider = MapFactory.create(mapOfStringAndProviderOfPlayerProvider);
this.gameMembersInjector =
Game_MembersInjector.create(mapOfStringAndPlayerProvider);
}
首先将两个provider装入Provider<Map<String,Privider<Player>>>中,然后将其转换成Provider<Map<String,Player>>。
注意最终返回的还是一个UnmodifiableMap!
@MapKey
我们直接来分析复合Map的情况。复合map其实和普通的map注入道理是一样的,不同点在于key值得构建。仔细看看上面我们在什么时候用到了key值?在将provider装入Provider<Map<String,Privider<Player>>>中时,使用了key值,一般情况下,这个key值是dagger直接从module中的provides中直接获取,但是对于复合map的情况,我们需要构建一个key对象。
this.mapOfGameInfoAndProviderOfStringProvider =
MapProviderFactory.<GameInfo, String>builder(1)
.put(GameInfoCreator.createGameInfo("game", 100.0F), getGameInfoProvider)
.build();
看put方法中,我们使用GameInfoCreator.createGameInfo方法创建了一个对象。
很显然GameInfoCreator是一个自动生成的类(我们从未定义过)
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class GameInfoCreator {
private GameInfoCreator() {}
@AutoAnnotation
public static GameInfo createGameInfo(String name, float price) {
return new AutoAnnotation_GameInfoCreator_createGameInfo(name, price);
}
}
这是一个很简单的类,我们用到了两个注解@Generated 和@AutoAnnotation,后者属于auto-value库,前者是java8中的一个类
javax.annotation.Generated
所以如果你在版本低于java8的环境下编译,就需要添加对于这个库的依赖,这就是在android中添加
provided 'javax.annotation:jsr250-api:1.0'
的原因。
至于具体它是怎么生成的,那就不是dagger得事情了,而是auto-value库的事情。