@Binds
@Binds注解用于为一个抽象类型依赖绑定其实现类。
假如我们现在有两个Model:AModel和BModel,都继承自BaseModel,我们希望将AModel注入到AView,将BModel注入到BView,但是现在View中用于接收依赖项的成员是BaseModel类型。
abstract class BaseModel
class AModel @Inject constructor() : BaseModel
class BModel @Inject constructor() : BaseModel
class AView {
@Inject
lateinit var model: BaseModel // 希望注入AModel
}
class BView {
@Inject
lateinit var model: BaseModel // 希望注入BModel
}
我们知道,Dagger是通过类型来确定要注入的依赖项的,如果直接使用上述代码,编译时会出现找不到BaseModel错误。
对于上面这个问题,我们可以使用provides-method来解决:
@Module
class AModule {
@Provides fun bindAModel(model: AModel): BaseModel = model
}
@Module
class BModule {
@Provides fun bindBModel(model: BModel): BaseModel = model
}
@Component(modules = [AModule::class])
interface AComponent
@Component(modules = [BModule::class])
interface BComponent
通过上述的改造后,我们就可以使用AComponent为AView注入AModel,使用BComponent为BView注入BModel。
这种方式虽然可以解决问题,但是Dagger会为每个provides-method生成一个工厂类,用在此处多少有些浪费了。为此Dagger提供了另一种解决方式,使用@Binds注解。
@Module
abstract class AModule {
@Binds abstract fun bindAModel(model: AModel): BaseModel
}
@Module
abstract class BModule {
@Binds abstract fun bindBModel(model: BModel): BaseModel
}
Dagger不会为@Binds标记的绑定方法生成对应的工厂类,@Binds注解在这里也仅作为标记。
需要注意的是,@Binds只能用在抽象方法上,并且Module类也要变成抽象类或者接口。另外,@Binds所在的Module里不允许定义其它非静态的provides-methods。
@BindsOptionalOf
@BindsOptionalOf用于注入可能为空的依赖项。该注解主要用于Java中注入空值,通过Java8的Optional可以安全的使用可空对象,在Kotlin中直接使用对应的可空类型即可。
在上文例子的基础上,假如我们有一个CView,该View暂时不需要注入对应的Model。但是为了和其它View保持相似的结构或者注入的位置在BaseView中,此时可能需要注入一个空值。此时我们可以使用@BindsOptionalOf。
class CView {
@Inject
public Optional<BaseModel> model; // CView希望接收一个空值
}
@Module
interface EmptyModelModule {
@BindsOptionalOf
BaseModel bindBModel(BModel model);
}
@Component(modules = {
EmptyModelModule.class
// , CModule.class // 等CModule准备好以后再解开注解,这之前依然可以正常注入。
})
interface BComponent {
void inject(CView view);
}
public static void main() {
CView view = new CView();
DaggerBComponent.create().inject(view);
view.model.getOrNull(); // 访问Model
}