Kotlin学习笔记——Dagger2

遇到的坑

1、别人都说使用@SubComponent方式时,可以使用相同的注解,但是我始终没有弄成功。比如本文最后一个例子,都采用@Singleton注解时,编译报错。

Dagger2是什么?

Dagger2是一款基于Java注解,在编译阶段完成依赖注入的开源库,主要用于模块间解耦,方便进行测试。

注解

@Component

标注接口,是依赖需求方和依赖提供方之间的桥梁。
被Component标注的接口在编译时会生成该接口的实现类(Dagger+Component名字),我们通过调用这个实现类的方法完成注入。

@Inject

1、用来标记需要依赖的变量。
2、用来标记无参构造函数,以便Dagger2在需要这个类实例的时候来找到这个无参构造函数并把相关实例构造出来,以此来为第一条中的变量提供依赖。
3、用来标记普通方法,该方法会在对象注入完成之后调用,可以根据这一特性因此做一些初始化的工作。

@Module

标注提供依赖的类。
在@Inject不能满足我们的需求时(1、比如javabean是第三方提供的,我们没法给它的无参构造函数添加@Inject注解。2、javabean的构造函数带参数。),使用@Module来标注提供依赖的类。
需要注意的是Dagger2查找依赖的规则:

步骤1:首先查找@Module标注的类中是否存在提供依赖的方法。
步骤2:若存在提供依赖的方法,查看该方法是否存在参数。
a:若存在参数,则按从步骤1开始依次初始化每个参数;
b:若不存在,则直接初始化该类实例,完成一次依赖注入。
步骤3:若不存在提供依赖的方法,则查找@Inject标注的构造函数,看构造函数是否存在参数。
a:若存在参数,则从步骤1开始依次初始化每一个参数
b:若不存在,则直接初始化该类实例,完成一次依赖注入。

@Provides

标注Module所标注的类中的方法。
该方法在需要提供依赖时被调用,从而把预先提供好的对象当做依赖给标注了@Inject的变量赋值;

@Scope

用于自定义注解,其实就是一个标记而已。
比如我们自定义了一个注解@ActivityScope,那么在@Provides注解的方法(假设此方法返回实例instance)上标记@ActivityScope,再到某个Component类上标记@ActivityScope,则实例instance的生命周期就和Component类实例的生命周期一样。
假如这个Component类实例是在Application中初始化的,那么instance就变成了全局单例。比如系统定义好的@Singleton注解,只是@Singleton的名字更有意义而已。
假如这个Component类实例是在Activity中初始化的,那么instance的生命周期就和Activity一样。

dependencies和@SubComponent

Dagger2 @Component 和@SubComponent 区别解惑

Android常用开源工具(2)-Dagger2进阶

我也参造写了个例子:
1、两种方式通用的部分:

/**
 * 它注解的实例和Component的生命周期一样
 */
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@Scope
annotation class ActivityScope
data class Info1(val name: String, val age: Int)
data class Info2(val name: String)

2、dependencies方式:

class DepActivity : AppCompatActivity() {
    @Inject lateinit var info1: Info1
    @Inject lateinit var info2: Info2

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val appContext: DepApplication = application as DepApplication
        DaggerDepActivityComponent.builder()
                .depActivityModule(DepActivityModule())
                .depApplicationComponent(appContext.applicationComponent)
                .build()
                .inject(this)
        Logger.e(info1)
        Logger.e(info2)
    }
}
/**
 * 注意:拥有dependencies依赖关系的 Component 是不能有相同 @Scope 注解
 * 所以这里采用@ActivityScope注解,而DepApplicationComponent中采用的是@Singleton注解
 */
@ActivityScope
@Component(modules = arrayOf(DepActivityModule::class), dependencies = arrayOf(DepApplicationComponent::class))
interface DepActivityComponent {
    // 为了让DepActivity可以使用DepActivityModule中的实例
    fun inject(activity: DepActivity)
}
@Module
class DepActivityModule {
    @ActivityScope
    @Provides
    fun provideInfo2() = Info2("DepActivityModule like info2")
}
class DepApplication : Application() {
    @Inject lateinit var info1: Info1
    val applicationComponent: DepApplicationComponent by lazy {
        DaggerDepApplicationComponent.builder()
                .depApplicationModule(DepApplicationModule(this))
                .build()
    }

    override fun onCreate() {
        super.onCreate()
        applicationComponent.inject(this)
        Logger.e(info1)
    }

}
@Singleton
@Component(modules = arrayOf(DepApplicationModule::class))
interface DepApplicationComponent {
    // 为了让DepApplication可以使用DepActivityModule中的实例
    fun inject(application: DepApplication)

    // 将DepApplicationModule中需要的实例暴露出来,以便于其他依赖于DepApplicationComponent的Component调用。
    // 如果不暴露出来,就无法调用。
    fun info1(): Info1
}
@Module
class DepApplicationModule(val application: DepApplication) {

    @Singleton
    @Provides
    fun provideApplication() = application

    @Singleton
    @Provides
    fun provideInfo1() = Info1("DepApplicationModule like info1", 18)
}

3、@SubComponent方式:

class SubActivity : AppCompatActivity() {
    @Inject lateinit var info1: Info1
    @Inject lateinit var info2: Info2

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val appContext: SubApplication = application as SubApplication
        appContext.applicationComponent
                .addSub(SubActivityModule())
                .inject(this)
        Logger.e(info1)
        Logger.e(info2)
    }
}
/**
 * 注意:拥有Subcomponent关系的 Component 是不能有相同 @Scope 注解
 * 所以这里采用@ActivityScope注解,而SubApplicationComponent中采用的是@Singleton注解
 */
@ActivityScope
@Subcomponent(modules = arrayOf(SubActivityModule::class))
interface SubActivityComponent {
    // 为了让SubActivity可以使用SubActivityModule中的实例
    fun inject(activity: SubActivity)
}
@Module
class SubActivityModule {

    @ActivityScope
    @Provides
    fun provideInfo2() = Info2("SubActivityModule like info2")

}
class SubApplication : Application() {
    @Inject lateinit var info1: Info1
    val applicationComponent: SubApplicationComponent by lazy {
        DaggerSubApplicationComponent.builder()
                .subApplicationModule(SubApplicationModule(this))
                .build()
    }

    override fun onCreate() {
        super.onCreate()
        applicationComponent.inject(this)
        Logger.e(info1)
    }

}
@Singleton
@Component(modules = arrayOf(SubApplicationModule::class))
interface SubApplicationComponent {
    // 为了让SubApplication可以使用SubApplicationModule中的实例
    fun inject(application: SubApplication)

    // 这里和dependencies依赖关系不同,不需要将SubApplicationModule中需要的实例暴露出来,可以直接调用SubApplicationModule中的实例。
    fun addSub(module: SubActivityModule): SubActivityComponent
}
@Module
class SubApplicationModule(val application: SubApplication) {

    @Singleton
    @Provides
    fun provideApplication() = application

    @Singleton
    @Provides
    fun provideInfo1() = Info1("SubApplicationModule like info1", 18)
}

你可能感兴趣的:(Android)