Dagger2 中的 Binds、IntoSet、IntoMap

1.@Binds

使用@Inject初始化对象时有一种特殊情况:需要初始化的是接口的实例,这时候需要特殊处理一下,就需要用到@Binds

1
2
3
4
5
@Module
interface IMainViewModule {
@Binds
abstract fun provideIMainView(main: IMainViewImpl): IMainView
}

这里使用 provideXXX() 方式提供接口实例,说明几点:

  • 方法中必须有参数且只能有一个,是接口的实现类
  • 实现类必须提供@Inject的构造或 Module中@Provides形式提供
  • 方法是抽象方法,不必写方法体
  • 使用@Binds代替@Provides
  • 由于方法是抽象的,所以类也要抽象或接口

IMainViewImpl.kt 的代码:

1
class IMainViewImpl @Inject constructor() : IMainView

2.@IntoSet

使用注入形式初始化 Set 集合时,可以在 Module 中多次定义一系列返回值类型相同的方法:

1
2
3
4
5
6
7
8
9
10
@Module
class AnimalModule {
@IntoSet
@Provides
fun provideElephant() = Animal("大象")

@Provides
@IntoSet
fun provideMonkey() = Animal("猴子")
}

Animal.kt 代码:

1
class Animal(var name: String)

上面的 provideElephant() 和 provideMonkey() 返回值类型都是 Animal,都使用了@IntoSet注释,多说一句,@Provides当然也要有,如果是接口用@Binds
初始化并使用:

1
2
3
4
5
6
7
8
@Inject
lateinit var set: MutableSet<Animal>

...//代码省略

set.forEach {
Log.i("Main", "--- ${it.name} ---")
}

kotlin 里面 MutableSet 代替 Java 中的 Set,上面代码运行可以输出:

1
2
--- 大象 ---
--- 猴子 ---

3.@IntoMap

@IntoSet区别不大,Map 多了一个 key

1
2
3
4
5
6
7
8
9
@Provides
@IntoMap
@IntKey(0)
fun provideFish() = Animal("鱼")

@Provides
@IntoMap
@IntKey(1)
fun provideHuman() = Animal("人")

@IntKey里面就是 Map 中的 key,providesXXX() 返回值是 key 对应的 value,如果 key 是 String 类型的,则使用@StringKey()输入 key,此外,还可以自定义 key:

1
2
3
4
5
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@MapKey
annotation class ZhuangBiKey(val f: Float)

初始化 map 并使用:

1
2
3
4
5
6
7
8
@Inject
lateinit var map: Map<Int, Animal>

...//代码省略

map.forEach {
Log.i("Main", "--- key:${it.key}\nvalue:${it.value.name} ---")
}

最后,说实话我觉得这样初始化一个 Set 或者 Map 效率不高,只不过为了别人这样写我们能看懂而已。其实我觉得整个 dagger2 都不咋地(发布时删掉这句)。


其他几篇的链接:
Dagger2 中的 Qualifier
Dagger2 中的 Scope、dependencies
Dagger2 中的 SubComponent
Dagger2 中使用 AndroidInjection 优化注入流程