Dagger2 中的 Scope、dependencies

Scope中文意思是范围,Dagger2 中的@Singleton是 Scope 的一种默认实现,点进去可以看到:

1
2
3
4
@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

上面是 Java 方式,如果我们自定义一个 Scope 就很简单了(kotlin 语言):

1
2
3
4
@Documented
@Scope
@Retention(RetentionPolicy.RUNTIME)
annotation class ZhuangBiScope

一个 Component 依赖另一个 Component 时需要用到 Scope,至于为什么 Component 之间要互相依赖,简单说下:一个项目里有很多功能模块,很多的 Activity,每个 Activity 都有对应的 Component,那么每个 Component 再对应多个 Module,最终工程会很庞大。有些 Module 可以共用,所以就需要dependencies关键字来依赖别的 Component。

比如 AnimalComponent 要依赖 BComponent

AnimalComponent.kt

1
2
3
4
5
@ZhuangBiScope
@Component(dependencies = [(BComponent::class)],modules = [(AppModule::class), (AnimalModule::class)])
interface AnimalComponent {
fun inject(secondActivity: SecondActivity)
}

AnimalComponent 需要依赖 BComponent,则@ZhuangBiScope注解在 AnimalComponent 上面。另外,AnimalComponent 包含的 AppModule 和 AnimalModule 里面的provideXX()方法如果有使用 Scope 修饰的(如 Singleton、ZhuangBiScope),则 AnimalComponent 也要用同样的 Scope 注解。且包含在同一个 Component 下的不同 Module 中provideXX()必须使用相同的 Scope。

AppModule.kt

1
2
3
4
5
6
@Module
class AppModule(var myApp: Application) {
@Provides
@ZhuangBiScope
fun providesApplication(): Application = myApp
}

AnimalModule.kt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Module
class AnimalModule {
@Provides
@ZhuangBiScope
fun providesDog(): Dog {
Log.e("abc", "----- AnimalModule Dog -----")
return Dog()
}

@Provides
@Tested("dog")
@ZhuangBiScope
fun providesCat(dog: Dog): Cat {
Log.e("abc", "----- AnimalModule Cat withdog -----")
return Cat(dog)
}

@Provides
@Tested("dog2")
fun providesCat2(dog: Dog): Cat {
Log.e("abc", "----- AnimalModule Cat withdog2 -----")
return Cat(dog)
}
}

上面的 providesCat2() 方法没有任何 Scope 注解。
接下来我们看看 BComponent:

1
2
3
4
5
6
7
8
@Singleton
@Component(modules = [(PersonModule::class), (StudentModule::class)])
interface BComponent {
fun inject(bActivity: BActivity)
fun person(): Person
fun provideStudent(): Student
// fun test(): String//会报错
}

包含两个 Module,一开始我只写了第一行的fun inject(bActivity: BActivity)结果总是报错,在这里卡了很久。
需要说明的是:

  • 当一个 Component 给别的 Component 依赖时,被依赖的 Component 要定义一些方法。这些方法的返回值类型和它包含的 Module 中方法返回类型相同。
  • 只有暴露的方法才能在依赖方的 Component 中使用。
  • 所有的暴露给依赖方的方法都是无参的。
  • 不能有多余的自定义方法(例如上面的 test 方法),因为多余的在 Module 中找不到对应方法。

举例说明,BComponent 包含 PersonModule 和 StudentModule,两者分别包含:

1
2
3
4
5
6
@Singleton
@Provides
fun providePerson(): Person = Person()

@Provides
fun provideStudent(): Student = Student()

当 AnimalComponent 所 inject 的类中需要用到上面这两个实例的时候,就需要在 BComponent 中注册两个方法给 inject 的类使用(方法名叫什么都无所谓):

1
2
fun person(): Person
fun provideStudent(): Student

这样才可以在 AnimalComponent 所 inject 的类中使用@Inject初始化 Person 和 Student 对象。


最后
项目源码


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