dagger2在android的简单使用

1,297 阅读2分钟

1. 简介

dagger2是一个基于java注解的依赖注入框架,通过框架为我们创建实例,来解决模块间的解耦以及提高系统的健壮性,可维护性。 网上有很多关于dagger2在java中使用的例子。那么我来介绍一下dagger2在android中是如何利用的。

使用时需要在Module的build.gradle文件中加入dagger2的库。

    def daggerVersion = "2.24"
    implementation "com.google.dagger:dagger-android:${daggerVersion}"
    implementation "com.google.dagger:dagger-android-support:${daggerVersion}"
    kapt "com.google.dagger:dagger-compiler:${daggerVersion}"
    kapt "com.google.dagger:dagger-android-processor:${daggerVersion}"
    annotationProcessor "com.google.dagger:dagger-compiler:${daggerVersion}"

当然还不能忘了加上apply plugin: 'kotlin-kapt'

2. dagger2在android中的应用范围

  1. context的自动注入
  2. Activity和Frragment的创建
  3. ViewModelFactory和ViewModel的创建
  4. 其他Module的创建(比如:MVVM中model实例的创建,retrofit的实例创建)
  5. 其他

3. dagger2的注解

3.1 @Inject

@inject有两个作用。

  1. 标记需要依赖注入的函数,用来告诉dagger2框架为调用它的地方提供注入
  2. 标记构造函数,dagger2会为它创建实例

例子:可用于ViewModelFactory的创建 标记在ViewModelFactory。

// ViewModelFactory的创建
class Factory @Inject constructor(
    private val name: Name,
    @ApplicationContext private val context: Context
) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass == MainActivityViewModel::class.java) {
            return MainActivityViewModel(name, context) as T
        }
        val className = modelClass.name
        throw IllegalArgumentException("Unknown ViewModel class : $className")
    }
}

在Activity中创建ViewModelFactory。

@Inject
lateinit var viewmodelFactory: MainActivityViewModel.Factory
private val viewModel: MainActivityViewModel by lazy {
    ViewModelProvider(this, viewmodelFactory).get(MainActivityViewModel::class.java)
}

3.2 @Module

标记dagger2来提供的依赖类,跟@inject的作用是一样的,但是使用条件不一样。我们是不能随意更改第三方库的源代码,这样我们就不能使用@inject,所以需要用@Module来代替标记。 在android中可以应用到retrofit,Activity等的创建。应用范围很广。

// 用于Activity的创建注入
@Module
abstract class MainActivityModule {
    @Binds
    abstract fun provideActivity(activity: MainActivity): FragmentActivity

    @Module
    abstract class Builder {
        @ContributesAndroidInjector(modules = [MainActivityModule::class])
        abstract fun contributeMainActivity(): MainActivity
    }
}

3.3 @Provides

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

// 创建提供context的实现类
@Provides
@Singleton
@ApplicationContext // 自定义的注解
internal fun provideApplicationContext(application: Application): Context {
    return application
}

3.4 @Component

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

// 为了可以在全局注入context
@Singleton
@Component(
    modules = [AndroidInjectionModule::class,
        MainActivityModule.Builder::class,
        AndroidSupportInjectionModule::class,
        ApiModule::class]
)
interface ApplicationComponent : AndroidInjector<MyApplication> {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: Application): Builder

        fun build(): ApplicationComponent
    }

    override fun inject(app: MyApplication)

}

// 被标注的类为ApplicationComponent, 所以在编译时生成的类为DaggerApplicationComponent
internal fun Application.createAppComponent() = DaggerApplicationComponent.builder()
    .application(this)
    .build()

3.5 @Singleton

通过使用@Singleton实现全局单例, 但是是否能提供单例还要取决于对应的@Component是否为一个全局对象。

3.6 @Qulifier

@Qulifier用于自定义注解,用于提示注入的类型。我们使用@Qulifier来自定义注解,然后通过自定义的注解去标注提供依赖的方法和依赖需求方。 自定义一个提供context的注解。

@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
@Qualifier
annotation class ApplicationContext

创建实现类。

// 创建提供context的实现类
@Provides
@Singleton
@ApplicationContext // 自定义的注解
internal fun provideApplicationContext(application: Application): Context {
    return application
}

使用自定义注解。

class Factory @Inject constructor(
    private val name: Name,
    @ApplicationContext private val context: Context // 用自定义注解进行注入
) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass == MainActivityViewModel::class.java) {
            return MainActivityViewModel(name, context) as T
        }
        val className = modelClass.name
        throw IllegalArgumentException("Unknown ViewModel class : $className")
    }
}

github: github.com/HyejeanMOON…