(11) Dagger2 @IntoSet case analysis

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, @Singletonannotations can only guarantee that the elements Zooin different Set<Animal>collection objects are the same, but cannot guarantee that the Set<Animal>objects are singletons.

  • @BindsAnnotation usage
    @BindsAnnotation is used to replace @Providesannotations.In the above case code, annotations are used to @Providesprovide objects for the syringe. Here's how to use @Bindsannotations.
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@ProvidesThere are still many subtle differences between annotations and annotations, and I think it will be more flexible to use with @Bindsannotations Dagger2.

Guess you like

Origin blog.csdn.net/MoLiao2046/article/details/106890265