这篇文章介绍如下内容
相关代码在这里DaggerDemo
- 两种建立Component之间联系的方式。
- @Component的Dependencies
- @Subcomponent
- @Scope和@Singleton
- @Qualifier(限定符)和@Named
两种建立Component之间联系的方式。
@Component的Dependencies
获取某些类需要用到其他类,比如说SharedPreferences,就需要上下文,所以这时候可以使用Dependencies
首先写一个提供Context的依赖Component
- 创建ActivityComponent,ActivityModule
@Component(modules = [(ActivityModule::class)])
interface ActivityComponent {
fun getContext():Context
}
@Module
class ActivityModule(private val context: Context) {
@Provides
fun provideContext():Context{
return context
}
}
会发现ActivityComponent 与之前MainComponent不同,并不是fun inject(activity: MainActivity)
,而是fun getContext():Context
- 这两种方式有如下的区别
- fun inject(需注入的类: 类名),如
fun inject(activity: MainActivity)
:这种方式下Dagger2会从目标类开始查找@Inject注解,自动生成依赖注入的代码,调用inject可完成依赖的注入。 - fun get类名():类名,如
fun getContext():Context
:这种方式下Dagger2会到生成目标类实例,供其它组件使用(如果Obj本身还包含其它依赖注入,也会自动生成对应实例)。
- fun inject(需注入的类: 类名),如
新建DependenciesComponent,DependenciesModule
- 在DependenciesComponent 通过dependencies来依赖ActivityComponent
@Component(dependencies = [(ActivityComponent::class)],modules = [(DependenciesModule::class)])
interface DependenciesComponent {
fun inject(activity:DependenciesActivity)
}
- 在DependenciesModule 中provideSharePreferences的方法参数使用Context
@Module
class DependenciesModule {
@Provides
fun provideSharePreferences(context: Context): SharedPreferences {
return context.getSharedPreferences("app", Context.MODE_PRIVATE)
}
}
在Activity完成初始化Dagger
初始化Dagger与之前不同,首先要初始化DaggerActivityComponent,再将其赋值给DaggerDependenciesComponent
class DependenciesActivity : AppCompatActivity() {
@Inject
lateinit var preferences: SharedPreferences
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_advanced)
initDagger()
preferences.edit().putString("test", "依赖").commit()
btn_dependencies.setOnClickListener {
Toast.makeText(this, preferences.getString("test", ""), Toast.LENGTH_SHORT).show()
}
}
private fun initDagger() {
val activityComponent = DaggerActivityComponent.builder()
.activityModule(ActivityModule(this))
.build()
DaggerDependenciesComponent.builder()
.activityComponent(activityComponent)
.dependenciesModule(DependenciesModule())
.build()
.inject(this)
}
}
@Subcomponent
新建Child,ChildModule,ChildComponent
class Child @Inject constructor() {
fun getChildName():String{
return "孩子"
}
}
@Module
class ChildModule{
@Provides
fun providesChild(): Child {
return Child()
}
}
@Subcomponent(modules = [(ChildModule::class)])
interface ChildComponent {
fun inject(activity: SubActivity)
}
ChildModule与之前相同,但是ChildComponent 的注解改为@Subcomponent
新建Parent,ParentModule,ParentComponent
class Parent @Inject constructor() {
fun getParentName():String{
return "父亲"
}
}
@Module
class ParentModule {
@Provides
fun providesParent(): Parent {
return Parent()
}
}
@Component(modules = [(ParentModule::class)])
interface ParentComponent {
fun addSub(module: ChildModule): ChildComponent
}
在ParentComponent 添加方法addSub将其与ChildComponent关联
在Activity完成初始化Dagger
class SubActivity : AppCompatActivity() {
@Inject
lateinit var parent: Parent
@Inject
lateinit var child: Child
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sub)
initDagger()
btn_sub.setOnClickListener {
Toast.makeText(this, parent.getParentName(), Toast.LENGTH_SHORT).show()
Toast.makeText(this, child.getChildName(), Toast.LENGTH_SHORT).show()
}
}
private fun initDagger() {
DaggerParentComponent.builder()
.parentModule(ParentModule())
.build()
.addSub(ChildModule())
.inject(this)
}
}
初始化与之前不同,先完成ParentComponent 的建造之后通过之前预留的addSub方法将ChildComponent与其连接
两种方式的总结
- @Component的dependencies 的能单独使用,而@Subcomponent必须由父级Component调用方法获取。
- @Component的dependencies 可以显示它依赖于那个Component, 而@Subcomponent的子级Component并不知道其的父级Component
@Scope和@Singleton
@Scope是用来管理依赖的生命周期的。而@Singleton则是@Scope的默认实现,不过它指的是不是单例,它的作用只是保证依赖在@Component中是唯一的
使用@Singleton
- 在ParentModule 和ParentComponent 增加@Singleton注解
@Singleton
@Component(modules = [(ParentModule::class)])
interface ParentComponent {
fun addSub(module: ChildModule): ChildComponent
}
@Module
class ParentModule {
@Singleton
@Provides
fun providesParent(): Parent {
return Parent()
}
}
- 在Activity中增加这些东西
@Inject
lateinit var parent1: Parent
@Inject
lateinit var parent2: Parent
btn_singleton.setOnClickListener {
Log.d("==", parent1.toString())
Log.d("==", parent2.toString())
}
之后你就可以看到在日志中看到这两个hash值是相同的,也就是同一个
parent1 = Parent@957fb47
parent2 = Parent@957fb47
然后你用同样的方式在使用Dependencies的ActivityComponent,ActivityModule中,然后它就报错了。
因为Dagger规定依赖的子Component(比如DependenciesComponent)也必须有注解
然后你给DependenciesComponent,DependenciesModule增加了@Singleton还是报错
因为Dagger规定不允许依赖的子Component使用同样的@Singleton,所以我们要自定义@Scope注解
自定义@Scope注解
自定义DependenciesScope使用在DependenciesComponent,DependenciesModule就可以了
@Scope
@Documented
@Retention(AnnotationRetention.RUNTIME) annotation class DependenciesScope
@Qualifier(限定符)和@Named
@Qualifier是限定符,而@Named则是基于String的限定符
当我有两个相同的依赖(都继承某一个父类或者都是先某一个接口)可以提供给高层时,那么程序就不知道我们到底要提供哪一个依赖,因为它找到了两个。
这时候我们就可以通过限定符为两个依赖分别打上标记,指定提供某个依赖。
@Named使用
- 有两个实现IJob的类
class AndroidProgrammer : IJob {
override fun work(context: Context) {
Toast.makeText(context, "工作内容:开发AndroidApp", Toast.LENGTH_SHORT).show()
}
}
class iOSProgrammer: IJob {
override fun work(context: Context) {
Toast.makeText(context, "工作内容:开发iOSApp", Toast.LENGTH_SHORT).show()
}
}
- 在MainModule中增加Provides的方法,并使用@Named注解
@Named("Android")
@Provides
fun provideAndroid():IJob{
return AndroidProgrammer()
}
@Named("iOS")
@Provides
fun provideiOS():IJob{
return iOSProgrammer()
}
- 在Activity中
切记,将@Named("Android")改为@field:[Named("Android")] 使用
@field:[Named("Android")]
@Inject
lateinit var android:IJob
@field:[Named("iOS")]
@Inject
lateinit var iOS:IJob
btn_name.setOnClickListener {
android.work(this)
iOS.work(this)
}
除此之外我们还可以自定义@Qualifier注解
自定义@Qualifier注解
- 新增@AndroidQualifier,@iOSQualifier
@Qualifier
@Documented
@Retention(AnnotationRetention.RUNTIME)
annotation class AndroidQualifier
@Qualifier
@Documented
@Retention(AnnotationRetention.RUNTIME)
annotation class iOSQualifier
- 在MainModule中
@AndroidQualifier
@Provides
fun provideAndroid2():IJob{
return AndroidProgrammer()
}
@iOSQualifier
@Provides
fun provideiOS2():IJob{
return iOSProgrammer()
}
- 在Activity中
@field:[AndroidQualifier]
@Inject
lateinit var android2:IJob
@field:[iOSQualifier]
@Inject
lateinit var iOS2:IJob