Hilt 是 Android 的依赖项注入库,可减少在项目中执行手动依赖项注入的样板代码。
Android Studio环境为 Android Studio Flamingo | 2022.2.1
Hilt最新版本为2.46
本章我们接着第一节后面继续学习Hilt的相关知识,主要集中在限定符Qualifier
和作用域Scope
两方面
Hilt为开发者提供了两个预定义限定符,分别为@ActivityContext
和@ApplicationContext
,看名字大致就可以知道是提供Activity
上下文和Application
上下文的功能,比如我们在别的类中需要引用一个Activity
的上下文参数,我们可以直接使用限定符来注入。
@AndroidEntryPoint
class QualifierActivity : BaseActivity<ActHiltBinding>() {
@Inject
lateinit var qualifier: Qualifier
override fun initViewBinding(): ActHiltBinding {
return ActHiltBinding.inflate(layoutInflater)
}
override fun onResume() {
super.onResume()
qualifier.test()
}
}
class Qualifier @Inject constructor(
@ActivityContext private val context: Context,
@ApplicationContext private val appContext: Context
) {
fun test() {
Log.d("Qualifier", "test ${context.packageName}, ${appContext.packageName}")
if (context is AppCompatActivity){
Log.d("Qualifier", "test: ${context::class.simpleName}")
}
}
}
# test com.example.myhilt, com.example.myhilt
# test: QualifierActivity
上面的Qualifier
类中传入了context
和appContext
参数,分别用限定符注解,这样我们创建实例的时候就不用单独传入参数了
在上一节的Module
中,我们使用@InstallIn
注解来声明了此模块作用的范围,此注解就是告知Hilt该模块在指定的作用域中只会生成一个实例
Android 类 | 生成的组件 | 作用域 |
---|---|---|
Application | SingletonComponent | @Singleton |
Activity | ActivityRetainedComponent | @ActivityRetainedScoped |
ViewModel | ViewModelComponent | @ViewModelScoped |
Activity | ActivityComponent | @ActivityScoped |
Fragment | FragmentComponent | @FragmentScoped |
View | ViewComponent | @ViewScoped |
带有 @WithFragmentBindings 注解的 View | ViewWithFragmentComponent | @ViewScoped |
Service | ServiceComponent | @ServiceScoped |
使用@Singleton
注解之后,在一个应用中周期内只会生成一个实例,通过代码来展示下具体实现
@AndroidEntryPoint
class ScopeActivity : BaseActivity<ActScopeBinding>() {
@Inject
lateinit var singletonTest: SingletonTest
override fun initViewBinding(): ActScopeBinding {
return ActScopeBinding.inflate(layoutInflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
findViewById<Button>(R.id.button).setOnClickListener {
startActivity(Intent(this, Scope2Activity::class.java))
}
}
override fun onResume() {
super.onResume()
singletonTest.test()
}
}
@Singleton
class SingletonTest @Inject constructor() {
fun test() {
Log.d("SingletonTest", "test: $this")
}
}
@AndroidEntryPoint
class Scope2Activity : BaseActivity<ActScopeBinding>() {
@Inject
lateinit var singletonTest: SingletonTest
override fun initViewBinding(): ActScopeBinding {
return ActScopeBinding.inflate(layoutInflater)
}
override fun onResume() {
super.onResume()
singletonTest.test()
}
}
# test: com.example.myhilt.scope.SingletonTest@196e6e4
# test: com.example.myhilt.scope.SingletonTest@196e6e4
SingletonTest
类使用了@Singleton
注解修饰,明确了它是一个单例对象,在应用中只会创建独一的实力,分别在两个Activity
中都注入了此对象,然后调用它test()
方法来打印它的信息,从日志中可以看出两次输出的为同一实例。
ActivityRetainedScoped
和ActivityScoped
这两个都是限定在一个Activity
中,但是Retained
的范围更广,比如在屏幕旋转时Activity
会销毁重建,Retained
会保存在内存中,重建之后依然使用的是同一个对象,而ActivityScope
会在销毁时也随之销毁,重建会重新创建一个实例,还是通过代码来展示具体实现
@AndroidEntryPoint
class ScopeActivity : BaseActivity<ActScopeBinding>(), DisplayManager.DisplayListener {
@Inject
lateinit var singletonTest: SingletonTest
@Inject
lateinit var activityScopeTest: ActivityScopeTest
@Inject
lateinit var activityRetainedScopeTest: ActivityRetainedScopeTest
override fun initViewBinding(): ActScopeBinding {
return ActScopeBinding.inflate(layoutInflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
findViewById<Button>(R.id.button).setOnClickListener {
startActivity(Intent(this, Scope2Activity::class.java))
}
}
override fun onResume() {
super.onResume()
val displayManager = this.getSystemService(DISPLAY_SERVICE) as DisplayManager
displayManager.registerDisplayListener(this, null)
singletonTest.test()
activityScopeTest.test()
activityRetainedScopeTest.test()
}
override fun onDisplayAdded(displayId: Int) {
}
override fun onDisplayRemoved(displayId: Int) {
}
override fun onDisplayChanged(displayId: Int) {
val display = windowManager.defaultDisplay
val rotation = display.rotation
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
Log.d(TAG, "onDisplayChanged: 竖屏")
} else if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
Log.d(TAG, "onDisplayChanged: 横屏")
}
}
}
@ActivityScoped
class ActivityScopeTest @Inject constructor() {
fun test() {
Log.d(TAG, "ActivityScopeTest test: $this")
}
}
@ActivityRetainedScoped
class ActivityRetainedScopeTest @Inject constructor() {
fun test() {
Log.d(TAG, "ActivityRetainedScopeTest test: $this")
}
}
# ActivityScopeTest test: com.example.myhilt.scope.ActivityScopeTest@ff1f74d
# ActivityRetainedScopeTest test: com.example.myhilt.scope.ActivityRetainedScopeTest@5edf202
# ActivityScopeTest test: com.example.myhilt.scope.ActivityScopeTest@ce2fd32
# ActivityRetainedScopeTest test: com.example.myhilt.scope.ActivityRetainedScopeTest@5edf202
# onDisplayChanged: 横屏
# ActivityScopeTest test: com.example.myhilt.scope.ActivityScopeTest@5b14b69
# ActivityRetainedScopeTest test: com.example.myhilt.scope.ActivityRetainedScopeTest@5edf202
# onDisplayChanged: 竖屏
ActivityScopeTest
类使用@ActivityScoped
注解修饰,ActivityRetainedScopeTest
类使用@ActivityRetainedScoped
注解修饰,并且都在Activity
注入,然后我们切换手机的横竖屏,从日志中可以看出,ActivityRetainedScopeTest
实例始终为同一个,而ActivityScopeTest
则每次旋转都会重新创建一个新的实例,在我们平时开发中,我们可以择优选择,适合自己项目的才是最好的。
其余的作用域都是类似:
@ViewModelScoped
注解修饰的对象和ViewModel
的生命周期是一致的;@FragmentScoped
注解修饰的对象和Fragment
的生命周期是一致的;@ViewScope
注解修饰的有两种,一种就是仅用@ViewSocpe
修饰,它的生命周期和View
一致,它可以在View
中使用,如果View
仅用@ActivityScoped
注解修改,那么此View
不仅可以在Activity
中使用,也可以在Fragment
中使用,但是如果View
额外加上@WithFragmentBindings
注解,那么此View
只能在Fragment
中使用,在Activity
中使用时会报一下错误:@WithFragmentBindings Hilt view must be attached to an @AndroidEntryPoint Fragment
此错误告诉我们,带有@WithFragmentBinding
注解的View
必须在Fragment
中使用,且Fragment
必须有@AndroidEntryPoint
注解修饰,大家在使用过程中按需添加。
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
一、面试合集
二、源码解析合集
三、开源框架合集
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓