使用Hilt实现Android依赖注入(DI:dependency-injection)

什么是依赖注入?
在软件工程中,依赖注入(dependency injection)的意思为,给予调用方它所需要的事物。 “依赖”是指可被方法调用的事物。依赖注入形式下,调用方不再直接使用“依赖”,取而代之是“注入” 。“注入”是指将“依赖”传递给调用方的过程。在“注入”之后,调用方才会调用该“依赖”[1]。传递依赖给调用方,而不是让让调用方直接获得依赖,这个是该设计的根本需求。
注:编程语言层次下,“调用方”为对象和类,“依赖”为变量。在提供服务的角度下,“调用方”为客户端,“依赖”为服务。
该设计的目的是为了分离关注点,分离调用方和依赖,从而提高可读性以及代码重用性。
依赖注射是控制反转的最为常见的一种技术。
引用自 维基百科
简介
依赖项注入是一种在编程中运用广泛的技术,非常适用于 Android 开发。遵循依赖项注入的原则可以为良好的应用架构奠定基础。
实现依赖项注入可为您带来以下优势:
- 重用代码
- 易于重构
- 易于测试
Hilt 是 Android 颇具特色的依赖项注入库,可减少在项目中使用手动依赖项注入时产生的样板代码。手动依赖项注入要求您手动构造每个类及其依赖项,并借助容器来重复使用和管理依赖项。
Hilt 通过为项目中的每个 Android 组件提供容器并自动为您管理容器生命周期,提供了一种在应用中执行依赖项注入的标准方法。这通过利用热门依赖项注入库 Dagger 实现。
前提条件
- 您有 Kotlin 语法经验。
- 您了解依赖项注入为什么对应用至关重要。
将 Hilt 添加到项目中
首先,将 hilt-android-gradle-plugin
插件添加到项目的根级 build.gradle
文件中:
buildscript {
...
ext.hilt_version = '2.28-alpha'
dependencies {
...
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
}
}
Tips:这里有一个坑,kotlin的版本如果是 1.5.0 的话,可能会在后续使用的编译时产生如下错误:
Execution failed for task ':app:kaptDebugKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask$KaptExecutionWorkAction
> java.lang.reflect.InvocationTargetException (no error message)
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
出现的原因:
Kotlin 的版本过高。
解决办法:
降低 Kotlin 的版本(我把 Kotlin 的版本改成 1.4.0 之后,然后编译通过了)。
参考链接
然后,为在 app
模块中使用 gradle 插件,我们应在 app/build.gradle
文件中指定它,具体方法为:将 gradle 插件添加到此文件的顶部、kotlin-kapt
插件之下:
...
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'
android {
...
}
然后,Hilt 依赖项会包含在项目的同一个 app/build.gradle
文件中:
...
dependencies {
...
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
}
最后,点击右上角的 Sync now 按钮同步项目,这个时候会下载包括 Hilt 在内的所有库。自此我们的准备工作就完成了。
在应用中使用 Hilt
在继承自 Application
类的上方添加 @HiltAndroidApp
注解。
@HiltAndroidApp
class App : Application() {
...
}
Hilt 模块
新建一个单例的 UserModel
类,然后在里面编写如下代码:
@Module
@InstallIn(ActivityComponent::class)
object UserModel {
@Provides
fun provideUser(): User {
return User("张三", "123456")
}
}
使用 Hilt 实现字段注入
Hilt 目前支持以下 Android 类型:
Application
(通过使用@HiltAndroidApp
)、Activity
、Fragment
、View
、Service
和BroadcastReceiver
。Hilt 仅支持扩展
FragmentActivity
(例如AppCompatActivity
)的 activity 和扩展 Jetpack 库Fragment
的 fragment,不支持 Android 平台中的Fragment
(现已弃用)。警告:Hilt 不支持保留的 fragment。
如要执行字段注入,请对您希望由 Hilt 提供(或注入)的 Android 类字段使用
@Inject
注解。警告:由 Hilt 注入的字段不能是私有字段。
将字段注入到 Activity 中
在 Activity 上添加 @AndroidEntryPoint
注解,即可使用依赖注入。
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var user: User
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Toast.makeText(this, "$user", Toast.LENGTH_SHORT).show()
}
}
将字段注入到 Fragment 中
将注入到 Fragment 中时,需要先在其附属的 Activity 上添加 @AndroidEntryPoint
注解,然后再在 Fragment 上添加 @AndroidEntryPoint
注解。
@AndroidEntryPoint
class HiltFragment: Fragment() {
@Inject lateinit var user: User
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.hilt_fragment, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Toast.makeText(context, "$user", Toast.LENGTH_SHORT).show()
}
}
Hilt & Dagger 注解
PDF文档下载链接
参考文章
java.lang.reflect.InvocationTargetException (no error message)