欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android Jetpack系列---Hilt

程序员文章站 2022-07-05 09:36:03
Hilt 是 Android 的依赖项注入库,可减少在项目中执行手动依赖项注入的样板代码Hilt 目前支持以下 Android 类:(1)Application(通过使用 @HiltAndroidApp)(2)Activity(3)Fragment(4)View(5)Service(6)BroadcastReceiver配置将hilt插件添加到根级 build.gradle 文件classpath 'com.google.dagger:hilt-android-gradle-plugin...

Hilt 是 Android 的依赖项注入库,可减少在项目中执行手动依赖项注入的样板代码
Hilt 目前支持以下 Android 类:
(1)Application(通过使用 @HiltAndroidApp)
(2)Activity
(3)Fragment
(4)View
(5)Service
(6)BroadcastReceiver

配置

将hilt插件添加到根级 build.gradle 文件

classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'

在 app/build.gradle 文件中添加以下依赖项

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'
}
    implementation "com.google.dagger:hilt-android:2.28-alpha"
    kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
android {
  ...
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

不带参数的依赖注入

(1)所有使用 Hilt 的应用都必须包含一个带有 @HiltAndroidApp 注释的 Application 类,这会触发 Hilt 的代码生成操作,生成的代码包括应用的一个基类,该基类充当应用级依赖项容器

@HiltAndroidApp
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
    }
}

(2)将依赖项注入 Android 类,注意Hilt注入的字段是不可以声明成private

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    @Inject
    lateinit var user: UserMsg
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        user.print()
    }
}

对应的UserMsg类只是做了简单的Log打印

class UserMsg @Inject constructor() {
    fun print() {
        Log.d("jay", "这是一个User")
    }
}

由此可见,我们在MainActivity中并没有去创建UserMsg实例,只是用@Inject声明了一下,然后就可以调用它的方法了

带参数的依赖注入

这里注意一点就行,UserMsg的构造函数中所依赖的所有其他对象都支持依赖注入了,那么UserMsg才可以被依赖注入
我们修改UserMsg类,现在UserMsg的构造函数中增加了一个LoveMsg参数,说明UserMsg是依赖LoveMsg的

class UserMsg @Inject constructor(val love: LoveMsg) {
    fun print() {
        Log.d("jay", "这是一个User的爱:${love}")
    }
}
class LoveMsg @Inject constructor() {
    
}

接口的依赖注入

首先定义一个接口,并实现它

interface Animal {
    fun walking()
    fun honking()
}
class Dog @Inject constructor() : Animal {
    override fun walking() {
        Log.d("jaydog", "行走的狗狗")
    }

    override fun honking() {
        Log.d("jaydog", "汪汪汪")
    }
}
class Snake @Inject constructor() : Animal {
    override fun walking() {
        Log.d("jaysnake", "滑滑滑滑滑")
    }

    override fun honking() {
        Log.d("jaysnake", "咕咕咕咕")
    }
}

新建一个抽象类

@Module
@InstallIn(ActivityComponent::class)
abstract class AnimalModule {

    @Binds
    abstract fun bindDog(dog: Dog): Animal
}

然后再回到UserMsg,成功打印结果

class UserMsg @Inject constructor(val love: LoveMsg) {

    @Inject
    lateinit var animal: Animal

    fun print() {
        Log.d("jay", "这是一个User的爱:${love}")
        animal.walking()
        animal.honking()
    }
}

Qualifier注解的使用

Qualifier注解的作用就是给相同类型的类或接口注入不同的实例
先定义两个注解

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class BindDog

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class BindSnake

修改AnimalModule

@Module
@InstallIn(ActivityComponent::class)
abstract class AnimalModule {

    @BindDog
    @Binds
    abstract fun bindDod(dog: Dog): Animal

    @BindSnake
    @Binds
    abstract fun bindSnake(snake: Snake): Animal
    
}

然后调用方法打印

class UserMsg @Inject constructor(val love: LoveMsg) {

    @BindDog
    @Inject
    lateinit var dog: Animal

    @BindSnake
    @Inject
    lateinit var snake: Animal

    fun print() {
        dog.walking()
        dog.honking()
        Log.d("jay", "这是一个User的爱:${love}")
        snake.honking()
        snake.walking()
    }
}

第三方类的依赖注入

就拿okhttp来说吧,在MainActivity中使用OkHttp发起网络请求,通常会创建一个OkHttpClient的实例,但是原则上OkHttpClient实例不应该由Activity去创建,所以也可以使用依赖注入,我们新建一个HttpModule类,给OkHttpClient类型提供实例

@Module
@InstallIn(ActivityComponent::class)
class HttpModule {
    @Provides
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient().newBuilder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .build()
    }
}

然后在MainActivity中去依赖注入OkHttpClient

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var okHttpClient: OkHttpClient
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

为Android类生成组件

对于您可以从中执行字段注入的每个 Android 类,都有一个关联的 Hilt 组件,您可以在 @InstallIn 注释中引用该组件。每个 Hilt 组件负责将其绑定注入相应的 Android 类,不过Hilt 不会为广播接收器生成组件,因为 Hilt 直接从 ApplicationComponent 注入广播接收器
Android Jetpack系列---Hilt

其中,ApplicationComponent提供的依赖注入实例可以在全项目中使用。因此,如果我们希望刚才在HttpModule中提供的OkHttpClient实例全项目使用,只需要这样修改

@Module
@InstallIn(ApplicationComponent::class)
class HttpModule {
    @Provides
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient().newBuilder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .build()
    }
}

组件的作用域

默认情况下,Hilt 中的所有绑定都未限定作用域。这意味着,每当应用请求绑定时,Hilt 都会创建所需类型的一个新实例,不过,Hilt 也允许将绑定的作用域限定为特定组件。Hilt 只为绑定作用域限定到的组件的每个实例创建一次限定作用域的绑定,对该绑定的所有请求共享同一实例

将绑定的作用域限定为某个组件的成本可能很高,因为提供的对象在该组件被销毁之前一直保留在内存中。请在应用中尽量少用限定作用域的绑定。如果绑定的内部状态要求在某一作用域内使用同一实例,或者绑定的创建成本很高,那么将绑定的作用域限定为某个组件是一种恰当的做法

Android Jetpack系列---Hilt

如果全局只需要一份,可以借助@Singleton注解

@Module
@InstallIn(ApplicationComponent::class)
class HttpModule {

    @Singleton
    @Provides
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient().newBuilder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .build()
    }
}

关于Context

class UserMsg @Inject constructor(@ActivityContext val context: Context) {

}
class UserMsg @Inject constructor(@ApplicationContext val context: Context) {

}

本文地址:https://blog.csdn.net/qq_45485851/article/details/110128769