Hilt学习笔记

依赖注入(DI),旨在为代码解耦,谷歌基于Dagger1开发出了Dagger2,然后专门为Android量身打造了Hilt,Hilt最明显的特征就是:1. 简单。2. 提供了Android专属的API。

1、引入
//根build.gradle文件
plugins {
    id 'com.google.dagger.hilt.android' version '2.44' apply false
}
//app的build.gradle文件
plugins {
    id 'kotlin-kapt'
    id 'com.google.dagger.hilt.android'
}
//开启java8特性
compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
//导入依赖
dependencies {
    ...
    implementation "com.google.dagger:hilt-android:2.44"
    kapt "com.google.dagger:hilt-compiler:2.44"
    ...
}
2、Hilt入口点

Hilt一共支持6个入口点

入口点对应注解
Application@HiltAndroidApp
Activity@AndroidEntryPoint
Fragment@AndroidEntryPoint
View@AndroidEntryPoint
Service@AndroidEntryPoint
BroadcastReceive@AndroidEntryPoint

除了Application的入口点对应注解为@HiltAndroidApp,其他五大入口点的对应注解均为@AndroidEntryPoint

使用示例

@HiltAndroidApp
class MyApplication : Application() {
    
}
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
    
}
3、无参构类造的使用
//在无参构造类添加注解@Inject,表明该类被Hilt托管,由Hilt来实例化
class Truck @Inject constructor() {
 
    fun deliver() {
        println("Truck is delivering cargo.")
    }
    
}
​
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
 
    //然后在其他类中就可以使用了,这里先声明一个延迟Trunk变量,然后在上面添加一个@Inject表示由Hilt来实例化
    @Inject
    lateinit var truck: Truck
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //代码中就可以正常调用Trunk类中的方法
        truck.deliver()
    }
 
}

4、有参构造类的使用
//可以看到我们这里的Trunk类中构造方法有了一个Driver类型的参数
class Truck @Inject constructor(val driver: Driver) {
 
    fun deliver() {
        println("Truck is delivering cargo. Driven by $driver")
    }
 
}
​
//所以我们这里需要在Driver类中添加一个@Inject注解,表示Driver类被Hilt托管,由Hilt来实例化
class Driver @Inject constructor() {
​
}
//然后Trunk就可以就跟前面的无参构造一样使用了

5、接口依赖注入
//我们这里定义了一个Engine接口,并且其中有两个方法
interface Engine {
    fun start()
    fun shutdown()
}
​
//然后定义了两个类GasEngine和ElectricEngine分别来实现Engine接口
class GasEngine @Inject constructor() : Engine {
    override fun start() {
        println("Gas engine start.")
    }
 
    override fun shutdown() {
        println("Gas engine shutdown.")
    }
}
​
class ElectricEngine @Inject constructor() : Engine {
    override fun start() {
        println("Electric engine start.")
    }
 
    override fun shutdown() {
        println("Electric engine shutdown.")
    }
}
//由于Engine是一个接口,当我们声明这个接口类型时,Hilt不知道我们需要什么样的具体类型,所以我们还需要进行下一步操作指明具体的对象类型
//这里定义一个抽象类,命名为EngineModule,意思为Engine接口提供具体的对象
//@Module注解,表示这一个用于提供依赖注入实例的模块。
//@InstallIn(ActivityComponent::class),就是把这个模块安装到Activity组件当中,即Activity以及Activity中包含的Fragment和View也可以使用,其他地方不能使用
@Module
@InstallIn(ActivityComponent::class)
abstract class EngineModule {
 
    @BindGasEngine//下面声明的注解,个人理解方便其他地方使用bindGasEngine这个方法来获取具体对象
    @Binds//这个方法绑定具体的对象类型,方法参数中传入什么类型,就返回什么类型,注意GasEngine必须继承/实现Engine
    abstract fun bindGasEngine(gasEngine: GasEngine): Engine
 
    @BindElectricEngine
    @Binds
    abstract fun bindElectricEngine(electricEngine: ElectricEngine): Engine
 
}

//在EngineModule这个抽象类文件中声明以下注解,然后将对应注解添加到上面对应方法上面,表示这个注解与具体的对象类型进行绑定
@Qualifier//给相同类型的类或接口注入不同的实例,限定符
@Retention(AnnotationRetention.BINARY)
annotation class BindGasEngine
 
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class BindElectricEngine
//然后具体在Truck类中使用Engine类型的对象
class Truck @Inject constructor(val driver: Driver) {
 
    @BindGasEngine//通过我们前面定义的注解显示声明我们需要的具体类型的对象
    @Inject
    lateinit var gasEngine: Engine
 
    @BindElectricEngine//通过我们前面定义的注解显示声明我们需要的具体类型的对象
    @Inject
    lateinit var electricEngine: Engine
 
    fun deliver() {
        gasEngine.start()//正常使用
        electricEngine.start()//正常使用
        println("Truck is delivering cargo. Driven by $driver")
        gasEngine.shutdown()
        electricEngine.shutdown()
    }
 
}
 
6、第三方类的依赖注入
1、直接使用OkHttpClient

例如我们想要使用OkHttp来访问网络资源,所以需要去构建一个OkHttpClient实例

//创建一个NetworkModule类用来提供OkHttpClient实例
@Module
@InstallIn(ActivityComponent::class)
class NetworkModule {
    //然后定义一个provideOkHttpClient方法用来提供OkHttpClient实例,这个方法上添加@Provides注解,表示Hilt来托管这个方法来实例化OkHttpClient对象
    @Provides
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .connectTimeout(20, TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.SECONDS)
            .writeTimeout(20, TimeUnit.SECONDS)
            .build()
    }
​
}
//使用
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
 
    @Inject
    lateinit var okHttpClient: OkHttpClient
    ...
 
}

2、直接使用Retrofit,通过Retrofit间接使用OkHttpClient
@Module
@InstallIn(ActivityComponent::class)
class NetworkModule {
    
    @Provides
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .connectTimeout(20, TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.SECONDS)
            .writeTimeout(20, TimeUnit.SECONDS)
            .build()
    }
    
    //由于上述定义了如何通过Hilt来获取OkHttpClient类型的对象,所以这里参数Hilt自动帮我们注入了
    @Provides
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl("http://example.com/")
            .client(okHttpClient)
            .build()
    }
 
}
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
 
    @Inject
    lateinit var retrofit: Retrofit
    ...
 
}

7、Hilt的组件作用域

对于可以从中执行字段注入的每个 Android 类(6个入口),都有一个关联的 Hilt 组件,可以在 @InstallIn 注解中引用该组件。每个 Hilt 组件负责将其绑定注入相应的 Android 类

使用方式,例:@InstallIn(ActivityComponent::class)

Hilt 组件注入器面向的对象Android类对应的作用域
SingletonComponentApplication@Singleton
ActivityRetainedComponent不适用@ActivityRetainedScoped
ViewModelComponentViewModel@ViewModelScoped
ActivityComponentActivity@ActivityScoped
FragmentComponentFragment@FragmentScoped
ViewComponentView@ViewScoped
ViewWithFragmentComponent带有 @WithFragmentBindings 注解的 View@ViewScoped
ServiceComponentService@ServiceScoped

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

8、在 Hilt 不支持的类中注入依赖项

引用:
Android Jetpack组件之Hilt使用_android hilt-CSDN博客

  • 14
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值