1 | @Provides @Singleton static Heater provideHeater(){ |
@Singleton 注解也可用于注解可注入类文档,提醒维护者,该类可能被多个线程使用。
1 | @Singleton |
由于在有向图中是通过组件实例
的实现来连接域实例,所以组件自身需要声明其作用域。举个栗子,组件中可以包含有@Singleton和@RequestScoped注解的绑定,然而两个注解有不同的生命周期,所以这样的组件就没多大意义了。在组件中使用域注解
1 | @Component(modules = DripCoffeeModule.class) |
组件可能被应用多个域注解,这表明他们有共同的别名域,组件可以绑定到任何一个声明的域中。
Reusable scope
有时你想限制被@Inject注解的构造器实例化的数量 或者 @Provides方法的调用次数,但在组件或者子组件的生命周期中你不需要保证精确的相同实例个数。但在Android 环境下,这一点还是很有必要。
对于那些需要被重用的绑定可以使用@Reusable 域注解。@Reusable域绑定注解并不会和哪些单个的组件建立关联,而是使用缓存来管理注解。
也就是说如果在一个组件中使用了@Reusable绑定安装了一个Module,但是实际上只有这一个组件的一部分使用了该绑定,那么就只有这一部分被缓存。同理,如果两个拥有不同父类的组件分别使用了绑定,那么他们就会被分别缓存。如果组件的父类已经缓存了当前类实例,那么子组件将重用该实例。
这里并不能保证组件只调用一次绑定,所以用@Reusable去绑定返回可变对象 或者 需要引用一个重要的相同实例就会很危险。所以如果不考虑分配次数,对无作用域的不可变对象使用@Reusable是安全的
1 | @Reusable // It doesn't matter how many scoopers we use, but don't waste them. |
Releasable references
当绑定中使用域注解的时候,表明组件类持有相关object的引用直到object被回收。像Android这种内存敏感的环境下,你希望当前未使用的域object在应用内存紧张的情况下可以被删除。
这种情况下,就可以使用@CanReleaseReferences注解
1 | @Documented |
当你决定在垃圾回收期间如果在相关域中的object没有被其他object使用的情况被删除,你可以在域中注入一个 ReleasableReferenceManager 类然后调用 releaseStrongReferences() 方法,使得组件持有这个类的 WeakReference
1 | @Inject @ForReleasableReferences(MyScope.class) |
同理,在内存压力不大的时候,可以通过调用 restoreStrongReferences()方法 存储任何没有被垃圾回收的缓存类的强引用。
1 | void highMemory() { |
Lazy injections
有时需要懒加载,例如绑定T,可以创建Lazy
1 | class GridingCoffeeMaker { |
Provider injections
有时需要返回多个实例而不是一个,当你有多个选项(如 Factories,Builders,等),一个选项是注入一个 Provider
1 | class BigCoffeeMaker { |
Note
: Provider
Qualifiers
有时单独类型不足以识别依赖。比如一个复杂的咖啡机应用只需要单独的热水器和热板加热器。
这种情况下添加一个 qualifier注解 @Qualifier。下面声明一个@Named。
1 | @Qualifier |
你可以自定义qualifier注解,或者只使用@Named注解。使用qualifiers注解字段或者参数。那么类型和qualifier注解都将被用于辨识依赖。
1 | class ExpensiveCoffeeMaker { |
注解相应的@Provides方法以提供备选值。
1 | @Provides @Named("hot plate") static Heater provideHotPlateHeater() { |
依赖项可能没有多个限定符注释。
Optional bindings
如果你希望某些并没有绑定到组件的依赖起作用,可以给Module添加 @BindsOptionalOf方法。
1 | @BindsOptionalOf abstract CoffeeCozy optionalCozy(); |
也就意味着 @Inject注解的构造器、成员和@Provides方法可以依赖一个*Optional
具体来说,可以注入以下任何一项:
1 | Optional<CoffeeCozy> |
如果子组件包含基础类型的绑定 那么组件中缺少的可选绑定可以出现在子组件中。
Binding Instances
构建组件时通常包含可用数据,例如,假设你有使用命令行参数的应用,你可能想把这些参数绑定到组件中。
也许你的应用需要一个单一参数展示用户名称就可以使用@UserName String注入。你可以给组件构造器添加一个方法注解 @BindsInstance 允许在该组件中注入实例
1 | @Component(modules = AppModule.class) |
Your app then might look like
1 | public static void main(String[] args) { |
上面的例子中,调用方法时,使用提供给builder的实例来进行@UserName String的注入。@BindsInstance注解方法必须在创建组件之前调用,并传递一个非空值。
如果@BindsInstance的参数有@Nullable注解,那么参数可以为空。此外 builder调用者会忽视调用方法,组件也将该注入实例视为空。
@BindsInstance 方法应优先使用于写一个 提供构造参数并立即提供这些值的 @Module 。
Compile-time Validation
dagger注解处理器非常严格,如果绑定不可用或者未完成都会引起编译时错误。比如,被调用的module中缺少Executor绑定。
1 | @Module |
编译它时会报一下错误:
1 | [ERROR] COMPILATION ERROR : |
这时候就需要添加@Provide方法 提供返回Executor的方法。
Compile-time Code Generation
dagger的注解处理器也会生成源文件如 CoffeeMaker_Factory.java或者CoffeeMaker_MembersInjector.java 这些文件都是dagger的实现细节.使用中都不会直接使用到。一般我们只需要关注一个以Dagger为前缀生成的组件。