当前位置:网站首页>Andorid Jetpack Hilt
Andorid Jetpack Hilt
2022-06-29 15:18:00 【灯塔@kuaidao】
前言
本blog 是学习Hilt官方文档后,随手记的笔记,欢迎一起探讨交流Hilt用法
Hilt 用到的注解和类
注解 | 解释 |
---|---|
@HiltAndroidApp | @HiltAndroidApp 会触发 Hilt 的代码生成操作,生成的代码包括应用的一个基类,该基类充当应用级依赖项容器 |
@EntryPoint | “hilt管理代码与非hilt管理代码之间的边界它是代码首次进入 Hilt 所管理对象的图的位置” |
@InstallIn | 指定要在其中安装入口点的组件 |
@AndroidEntryPoint | 充当组件持有者 |
EntryPointAccessors | 访问入口点工具 |
@ApplicationContext | 预定义限定符 |
@ActivityContext | 预定义限定符 |
DFM (动态功能模块) | |
@Inject | 提供依赖的对象 |
@WorkerInject | WorkManager注入 |
@Assisted | WorkManager注入 |
@Singleton | 限定作用域 |
Hilt 模块 @Module [email protected] 注释
解决问题:
1.不能通过构造函数注入接口
2.不能通过构造函数注入不归您所有的类型(外部库的类)
解决思路:
@Module注释的Hilt模块类里面的@Binds注释的函数会告知 Hilt 如何提供某些类型的实例
示例:
@Module
@InstallIn(ActivityComponent::class) 依赖项目注入所有拓展自ActivityComponent的子类
abstract class AnalyticsModule {
@Binds
abstract fun bindAnalyticsService(
analyticsServiceImpl: AnalyticsServiceImpl
): AnalyticsService
}
说明:在 Hilt 模块内创建一个带有 @Binds 注释的抽象函数(@Binds 注释会告知 Hilt 在需要提供接口的实例时要使用哪种实现),
带有@Binds的函数会向 Hilt 提供以下信息:函数返回类型会告知 Hilt 函数提供哪个接口的实例。
函数参数会告知 Hilt 要提供哪种实现。
使用 @Provides 注入实例
解决问题:
1.Retrofit、OkHttpClient、Room或者必须使用构建器模式创建实例,也同样无法使用构造器函数注入
解决思路:
@Provides注释函数会向 Hilt 提供以下信息
- 函数返回类型会告知 Hilt 函数提供哪个类型的实例。
- 函数参数会告知 Hilt 相应类型的依赖项。
- 函数主体会告知 Hilt 如何提供相应类型的实例。每当需要提供该类型的实例时,Hilt 都会执行函数主体。
示例:
@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {
@Provides
fun provideAnalyticsService(
// Potential dependencies of this type
): AnalyticsService {
return Retrofit.Builder()
.baseUrl("https://example.com")
.build()
.create(AnalyticsService::class.java)
}
}
为同一类型提供多个绑定
解决问题:
1.以依赖项的形式提供同一类型的不同实现
解决思路:
您可以使用限定符为同一类型定义多个绑定
限定符是一种注释,当为某个类型定义了多个绑定时,您可以使用它来标识该类型的特定绑定。
示例步骤:
1.定义要由于为@Binds 或 @Provides 方法添加注释的限定符
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AuthInterceptorOkHttpClient
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OtherInterceptorOkHttpClient
@Module
@InstallIn(ApplicationComponent::class)
object NetworkModule {
@AuthInterceptorOkHttpClient
@Provides
fun provideAuthInterceptorOkHttpClient(
authInterceptor: AuthInterceptor
): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(authInterceptor)
.build()
}
@OtherInterceptorOkHttpClient
@Provides
fun provideOtherInterceptorOkHttpClient(
otherInterceptor: OtherInterceptor
): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(otherInterceptor)
.build()
}
}
调用示例:
系统类中,自定义类中,hiltModule中
// As a dependency of another class.
@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {
@Provides
fun provideAnalyticsService(
@AuthInterceptorOkHttpClient okHttpClient: OkHttpClient
): AnalyticsService {
return Retrofit.Builder()
.baseUrl("https://example.com")
.client(okHttpClient)
.build()
.create(AnalyticsService::class.java)
}
}
// As a dependency of a constructor-injected class.
class ExampleServiceImpl @Inject constructor(
@AuthInterceptorOkHttpClient private val okHttpClient: OkHttpClient
) : ...
// At field injection.
@AndroidEntryPoint
class ExampleActivity: AppCompatActivity() {
@AuthInterceptorOkHttpClient
@Inject lateinit var okHttpClient: OkHttpClient
}
最佳做法:
如果对某一个类型添加限定符@Qualifier,应向提供该依赖项的所有可能的方式添加限定符。避免遗漏造成注入错误的依赖项。
@Inject 告知注入位置,@ActivityContext 预定义限定符,系统默认提供
java注解可应用于形参(PARAMETER,)和local_paramter 本地变量
为 Android系统类生成默认的组件
@InstallIn 可以关联的组件
ApplicationComponent | Application |
ActivityRetainedComponent | ViewModel |
ActivityComponent | Activity |
FragmentComponent | Fragment |
ViewComponent | View |
ViewWithFragmentComponent | 带有 @WithFragmentBindings 注释的 View |
ServiceComponent | Service |
示例:
@Module
@InstallIn(xxxComponent::class)
class xxxModule{
@Binds
或
@Provides
}
因为 Hilt 直接从 ApplicationComponent 注入广播接收器.
作用域
解决问题:
- 限制依赖的使用范围,在限制范围内依赖只初始化一次。避免重复创建浪费资源
- 依赖只在某一个作用域有效。
解决思路:
前两个需要着重查看下,hilt提供的作用域。
Application | ApplicationComponent | @Singleton |
View Model | ActivityRetainedComponent | @ActivityRetainedScope |
Activity | ActivityComponent | @ActivityScoped |
Fragment | FragmentComponent | @FragmentScoped |
View | ViewComponent | @ViewScoped |
Service | ServiceComponent | @ServiceScoped |
hilt支持注入的类,Android类,四大组件viewModel,View
上面介绍在构造函数中不能注入的对象或者其他不属于应用的第三方类图的对象,通过build来构建。下面介绍在Hilt不支持的类中注入依赖项
对于不支持的类型,定义入口点绑定组件形式,然后通过类检索组件,获取组件中的类型
比如:ContentProvider 中要使用Hilt提供的依赖项
解决问题:
- 不支持的类想使用hilt提供依赖对象
解决思路:访问入口点
- 使用@EntryPoint注释 @InstallIn(安装类),定义接口及需要提供的对象引用。声明在不支持的类中
示例
class ExampleContentProvider : ContentProvider() {
@EntryPoint
@InstallIn(ApplicationComponent::class)
interface ExampleContentProviderEntryPoint {
fun analyticsService(): AnalyticsService
}
...
}
多模块应用中使用Hilt
DFM 如何设置依赖,通过在主模块中设置入口点(与非动态模块设置依赖方向相反),设置Dagger模块依赖主模块功能点 放入功能模块,功能模块使用drgger来构建。
手动添加依赖注入
- 首先在一个类中创建所有的依赖对象,并拼装起来使用
- 为了复用,将拼装的逻辑抽取到服务定位器中进行全局统一管理
- 为了不同的界面流程需要创建不同的对象依赖。将对象的创建放入服务定位器中,并且创建工厂方法来对外提供对象
- 对于不同的业务流程,需要创建不同的依赖容器,并且绑定界面(Activity/Fragment)生命周期,在onCreate()创建在对应的Destroy()销毁
- 特殊情况需要在配置变更后保留对象状态,需要使用状态容器,生命周期绑定依赖容器和ui界面组件推荐使用生命周期管理工具LifeCycle
优点:
- 依赖注入对于创建可扩展且可测试的Android应用是一项合适的技术
- 将容器作为在应用内不同部分共享各个类的实例的一种方式,以及使用工厂创建各个类实例的集中位置
- 手动依赖项注入要求您手动构造每个类及其依赖项,并借助容器和工厂重复使用和管理依赖项。
缺点:
- 应用变大,流程变多,不同的界面流程需要维护不同的容器创建销毁,工厂方法的维护。
- 将会编写大量的样板代码,很容易出错,生命周期管理操作不当会产生微小错误和内存泄露
手动注入需要写模板代码,多模块依赖顶层模块构建对象,需要依赖到不同子模块。 依赖管理,依赖范围管理,依赖生命周期管理,依赖复用。需要考虑
问题
- 比方说,我有一个类A,我想通过构造函数或者传递参数方式注入类B应该怎么做?
- 比方说,程序代码需要用到一个外部库Retrofit或者OkHttp对象或者接口(控制翻转),怎么声明依赖关系。
总结:
hilt基于Dagger提供一套标准依赖注入做法,Hilt优化了Dagger依赖注入的功能,减少了样版代码的编写,依赖注入主要有两种方式,构造函数注入是最常用的,而参数注入使用优先级低于构造函数注入,对于接口,三方工具库等不能修改源码的依赖注入,需要创建Hilt模块,并使用@Module @Installin(依赖安装的类::class),@Provider(sdk的Builder构造),@Binds(接口,抽象类)注释解决依赖传递问题。
hilt用法xmind 脑图
边栏推荐
- 雷达基本组成
- Scroll,你玩明白了嘛?
- Lumiprobe click chemistry - non fluorescent alkyne: hexanoic acid STP ester
- postgresql源码学习(25)—— 事务日志⑥-等待日志写入完成
- MySQL定时整库备份&滚动删除指定日期前的备份数据
- "Game engine shallow in shallow out" 98 Substancepainer plug-in development
- Classe d'outils commune de fichier, application liée au flux (enregistrement)
- CKS CKA ckad change terminal to remote desktop
- PyTorch 二维多通道卷积运算方式
- Northwestern Polytechnic University attacked by overseas e-mail
猜你喜欢
第九章 APP项目测试(4) 测试工具
Pytorch two-dimensional multi-channel convolution operation method
Lumiprobe reactive dye miscellaneous dye: BDP FL ceramide
Middle order and post order traversal to construct binary tree [recursive partition interval and backtracking splicing subtree + similarity and difference between middle post order and middle pre orde
MCS: discrete random variable - Hyper geometric distribution
Lumiprobe 活性染料丨氨基染料:花青5胺
Lumiprobe 点击化学丨非荧光炔烃:己酸STP酯
Imgutil image processing tool class, text extraction, image watermarking
MCS: multivariate random variable - discrete random variable
Lumiprobe deoxyribonucleic acid alkyne DT phosphimide
随机推荐
Unity C basic review 27 - delegation example (p448)
雷达天线简介
Development and application of NFT chain Games: Six noteworthy NFT trends in 2022
雷达的类型
Solution to the problem that the assembly drawing cannot be recognized after the storage position of SolidWorks part drawing is changed
Is it reliable to invest in REITs funds? Is REITs funds safe
遥感典型任务分析
MySQL为什么选择B+树存储索引
从雷达回波中可获取的信息
MCS: discrete random variable Poisson distribution
Lumiprobe 点击化学丨非荧光炔烃:己酸STP酯
Hi,你有一份Code Review攻略待查收
Lumiprobe reactive dye cycloalkyne dye: af488 dbco, 5 isomer
欧标插头EN50075测试项目
Rust基础知识
GWD:基于高斯Wasserstein距离的旋转目标检测 | ICML 2021
Uncover the practice of Baidu intelligent test in the field of automatic test execution
LeetCode笔记:Weekly Contest 299
使用自定义注解实现Redis分布式锁
JS 会有变量提升和函数提升