Android Jetpack系列---Hilt
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 注入广播接收器
其中,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 只为绑定作用域限定到的组件的每个实例创建一次限定作用域的绑定,对该绑定的所有请求共享同一实例
将绑定的作用域限定为某个组件的成本可能很高,因为提供的对象在该组件被销毁之前一直保留在内存中。请在应用中尽量少用限定作用域的绑定。如果绑定的内部状态要求在某一作用域内使用同一实例,或者绑定的创建成本很高,那么将绑定的作用域限定为某个组件是一种恰当的做法
如果全局只需要一份,可以借助@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
推荐阅读
-
小米A3系列获FCC认证:搭载骁龙665 运行原生Android
-
Jetpack系列:Paging组件帮你解决分页加载实现的痛苦
-
Android 10源代码确认谷歌Pixel 4系列配备90Hz屏:下月发
-
带你了解Android Jetpack
-
小米A系列已是全球Android One手机销量冠军
-
Android Wear首款街头艺术系列表盘应用上架Google Play
-
[build.gradle配置系列(一)]android studio根据版本号动态生成apk名
-
Android Jetpack-Navigation 使用中参数的传递方法
-
Appium python自动化测试系列教程之关于Android知识的讲解(三)
-
基于Android 11打造!魅族17系列将升级全新Flyme 8