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中的应用范围
- context的自动注入
- Activity和Frragment的创建
- ViewModelFactory和ViewModel的创建
- 其他Module的创建(比如:MVVM中model实例的创建,retrofit的实例创建)
- 其他
3. dagger2的注解
3.1 @Inject
@inject有两个作用。
- 标记需要依赖注入的函数,用来告诉dagger2框架为调用它的地方提供注入
- 标记构造函数,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…