Dagger2 研习(二)

@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库的事情。

 

转载于:https://my.oschina.net/zzxzzg/blog/1541917

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值