Dargger2:@Binds使用

144 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 8 天,点击查看活动详情

image.png 上次我们讲了如何注入一个interface,注入一个interface必须要在module中提供一个provider方法,现在还有另外一种方法提供一个interface的实例对象,那就是使用@Binds。看看下面的例子。

我们有一个interface:

interface Work {
    fun  getWorkName():String
}

Interface有两个实例:

class Farmer @Inject constructor():Work {
    override fun getWorkName(): String {
        return  "farmer"
    }
}
class Engineer @Inject constructor():Work {
    override fun getWorkName(): String {
        return "Engineer"
    }
}

一个是Framer类,一个是Engineer类,里面又一个getWorkName的方法。如果按照以前的方法方法就需要这样子做:

@Provides
@Named("Farmer")
fun providerFarmer():Work{
    return Farmer()
}

在provider的实现里面实例化子类。假设如果Farmer需要传入一个Doing类:

class Doing @Inject constructor() {
    fun doingSomething(){
​
    }
}

那么我们provider的方法就要跟踪修改:

@Provides
@Named("Farmer")
fun providerFarmer(doing: Doing):Work{
    return Farmer(doing)
}

调用的地方:

Log.i("daggerExample","farmer get my name:${farmer.getWorkName()}")
Log.i("daggerExample","farer what  am I do:${farmer.doing.doingSomething()}")
Log.i("daggerExample","engineer get my name:${engineer.getWorkName()}")

这样就会比较麻烦,任何一个参数的修改都会牵扯到provider方法的修改。但是现在如果有了@Binds的方法,就会变的简单很多:

@Binds
@Named("Farmer")
abstract fun bindFarmerWork(farmer: Farmer):Work
​
@Binds
@Named("Engineer")
abstract fun bindEngineerWork(engineer: Engineer):Work

首先前面当然是要加上@Binds,方法也必须是abstract的,第一个参数是需要实例化的类,这样就完成了。当然Farmer里面传入的参数也必须是要带注解的,要不然也没有办法注入呀。同时还需要注意的是其所在的module也必须是abstract或者变成interface,例如:

@Module
abstract class BindExampleModule {
    @Binds
    @Named("Farmer")
    abstract fun bindFarmerWork(farmer: Farmer):Work
​
    @Binds
    @Named("Engineer")
    abstract fun bindEngineerWork(engineer: Engineer):Work
}

这里因为返回相同的对象所以需要使用Named进行重命名。

带@Binds的module里面不能再提供provider的方法了,如果同时有就会提示错误:

 A @Module may not contain both non-static and abstract binding methods
                ^

我们看看dagger生成的代码:

private MainActivity injectMainActivity(MainActivity instance) {
  MainActivity_MembersInjector.injectFarmer(instance, farmer());
  MainActivity_MembersInjector.injectEngineer(instance, new Engineer());
  return instance;
}

最终和使用provider的方式是一样的,当然也可以使用scope限定他的作用域了。