Dagger2 Tips

20210806 Dagger2 Tips

  1. @Inject是javax中的annotation,可以用作一般的构造方法,field等。不能用在:
    1. 接口上(因为接口是不能被构造的)
    2. 第三方的类(你无法annotate他们)
    3. 需要进一步配置的类
  2. @Provides,针对上边的情况就可以用到Provides Annotation来定制化的去构造需要的实例对象
  3. @Binds注解在简单对象构造的时候会觉得和@Provides的功能有所类似。但实际上其使用更加简单,可以认为其是简化了@Provides的一种用法:

@Provides static Heater provideHeater(E1ectricHeater heater ) {  return heater;

这种case的意思是,当需要Heater这个接口类型的实体时,用ElectricHeater的实现去返回(一定的,ElectricHeater的constructor是标记了@Inject)。简单将,这种case变成一句话就是某个接口由哪个实现来提供,那么可以通过@Binds简化为:

@Binds Heater bindHeater (ElectricHeater impl) ;

综上,推荐这种case下优先使用@Binds

  1. 依赖图构建的起点对于普通Java程序来说是main方法,对于Android程序来说就是Application的onCreate生命周期
  2. 命名规则上,Provides的方法就应该以provide开头,bind就是bind开头,而module就是module结尾
  3. 依赖图的根(root)是一个包含若干方法的接口,这里的方法是不能有参数的,而且返回值应该是返回响应的类型(被其他模块需要的类型实例),这样接口文件标记上@Component注解就ok了,然后在其modules属性中传入所有module的类,Dagger2就能自动的生成全依赖图了
  4. 每个应用只可能有一个Component,可以有多个Module
  5. 开发者在调用Component(如Android的Application的onCreate时),要记得,Dagger2给自动生成的文件是带有Dagger开头的,所以直接调用相关类即可(如你的类叫做CoffeeShop,那么Dagger为你生成的就是DaggerCoffeeShop)。需要调用它的builder方法来构建。如果你的Component类并不是顶级类,那么Dagger生成类时会加入下划线
  6. Scope是说某依赖在那个范围内生效,如果不标记的话,在当前的Component中能生效,或者是标记的Scope也符合当前的Component的话也能够生效
  7. Component可以拥有子Component
  8. @Singleton注解所标记的@Provides方法、@Inject的类都会被用作单例。Dagger2使用singleton的方法是用类静态全局变量的方法,故而没有线程竞争的问题,可以放心使用
  9. 因为Dagger2把依赖图中声明了领域配置的实例与Component实现实例关联在一起,所以组件本身也需要声明其所代表的领域(Scope)。所谓Scope,其背后代表其中的实例生命周期不一样。声明Scope的方法是在Component的接口文件上做标记(@Component的modules参数,即代表有哪些Module在这个Component下)。Singleton也算是一个Scope修饰,表明这个实例全局就只有一个
  10. 可复用——@Reusable。首先,这不是单例(Singleton),不能保证在scope内始终是一个实例(否则就singleton就好了),但是还可以限制@Inject和@Provides的构造和调用次数。
  11. Lazy这个类是个泛型,其声明是Lazy<T>,如果你为这样的field标记了singleton,那么每个人都会拿到同一个Lazy实例,如果未标记Singleton而是默认的scope的话,那么每个人拿到的Lazy实例是不一样的。但是无论如何,他们最后拿到的潜在的T对象实例都会是一个,因为Lazy的意思就是只有在第一次get行为被触发的时候T实例才会被构建,从今往后任何的get都会返回同一个实例
  12. Provider<T>是可以保证每次其T的实例都会被重新构造,@Provides并不能保证。但是如果标记了@Singleton,那么就没有意义了,因为总会是同一个T实例
  13. multibinding,多绑定(@IntoSet、@IntoMap) https://dagger.dev/dev-guide/multibindings
  14. multibinding的@IntoMap比IntoSet会复杂一些,如果你想要把一些依赖加入一个Map,而且它的key在编译时是已知的,那么就可以使用@IntoMap了。使用方法是在@Provides所标注的方法中添加注解@IntoMap,然后再添加一个自定义的annotation,这个annotation是用来定义map的key的。自定义的annotation中要标记上dagger的@MapKey这个注解,表示这个annotation是个map key,此自定义annotation的value就可以用作后续从map中获取实例的key,只要符合annotation的定义就可以,什么值都行。也可以不用自定义的annotation,而用Dagger2中定义好的,有两个@StringKey(用来定义简单的字符串key),@ClassKey(以类为key)。
  15. 全局只有一个Component,但可以有多个sub-Component,sub-Component会被自动收到到这个全局主的Component上
  16. @BindsInstance vs @Bind。@Bind是用在@Module中,用来给抽象方法定义,说明接口和实现的关系。而@BindsInstance是在@Component中,用来表示此Component中某个实现是绑定到哪个实例上,需要由开发者使用时显式设置进去(通过builder)
  17. 注意,Lazy(interface)在kotlin的包中也有,需要引入dagger包中的,否则会提示失败