Hilt的使用(依赖注入的基础知识)一

一、前言

Hilt是Android的依赖注入库,是依赖倒置思想的体现,主要用于项目的解耦操作。这篇文章主要是对依赖注入进行个记录,并没有使用Hilt。内容都是来自于Android Develop文档。下一篇正式开始使用时候才进行实际操作时候使用,该文的主要目的是为了使文章系列形成连贯性,其次是为了避免查找官方文档麻烦,再次是为了给不熟悉依赖注入的人一个了解的机会。还有就是防止个别地方网络不好访问不到官方网址

依赖项注入 (DI) 是一种广泛用于编程的技术,非常适用于 Android 开发。遵循 DI 的原则可以为良好的应用架构奠定基础。

实现依赖项注入可为您带来以下优势:

  • 重用代码
  • 易于重构
  • 易于测试

依赖项注入基础知识

在专门介绍 Android 中的依赖项注入之前,本页提供了依赖项注入工作原理的总体概览。

什么是依赖项注入?

类通常需要引用其他类。例如,Car 类可能需要引用 Engine 类。这些必需类称为依赖项,在此示例中,Car 类依赖于拥有 Engine 类的一个实例才能运行。

类可通过以下三种方式获取所需的对象:

  1. 类构造其所需的依赖项。在以上示例中,Car 将创建并初始化自己的 Engine 实例。
  2. 从其他地方抓取。某些 Android API(如 Context getter 和 getSystemService())的工作原理便是如此。
  3. 以参数形式提供。应用可以在构造类时提供这些依赖项,或者将这些依赖项传入需要各个依赖项的函数。在以上示例中,Car 构造函数将接收 Engine 作为参数。

第三种方式就是依赖项注入!使用这种方法,您可以获取并提供类的依赖项,而不必让类实例自行获取。

二、未使用依赖注入

下面是一个示例。在不使用依赖项注入的情况下,要表示 Car 创建自己的 Engine 依赖项,代码如下所示:

class Car {

    private val engine = Engine()

    fun start() {
        engine.start()
    }
}

fun main(args: Array) {
    val car = Car()
    car.start()
}

在这里插入图片描述

这并非依赖项注入的示例,因为 Car 类构造了自己的 Engine。这可能会有问题,原因如下:

  • CarEngine 密切相关 - Car 的实例使用一种类型的 Engine,并且无法轻松使用子类或替代实现。如果 Car 要构造自己的 Engine,您必须创建两种类型的 Car,而不是直接将同一 Car 重用于 GasElectric 类型的引擎。

  • Engine 的强依赖使得测试更加困难。Car 使用 Engine 的真实实例,因此您无法使用测试替身针对不同的测试用例修改 Engine

三、使用构造函数或字段进行依赖注入

如果使用依赖项注入,代码是什么样子的呢?Car 的每个实例在其构造函数中接收 Engine 对象作为参数,而不是在初始化时构造自己的 Engine 对象:

class Car(private val engine: Engine) {
    fun start() {
        engine.start()
    }
}

fun main(args: Array) {
    val engine = Engine()
    val car = Car(engine)
    car.start()
}

main 函数使用 Car。由于 Car 依赖于 Engine,因此应用会创建 Engine 的实例,然后使用它构造 Car 的实例。这种基于 DI 的方法具有以下优势:

  • 重用 Car。您可以将 Engine 的不同实现传入 Car。例如,您可以定义一个想要 Car 使用的名为 ElectricEngine 的新 Engine 子类。如果您使用 DI,只需传入更新后的 ElectricEngine 子类的实例,Car 仍可正常使用,无需任何进一步更改。

  • 轻松测试 Car。您可以传入测试替身以测试不同场景。例如,您可以创建一个名为 FakeEngineEngine 测试替身,并针对不同的测试进行配置。

在这里插入图片描述

Android 中有两种主要的依赖项注入方式:

  • 构造函数注入。这就是上面描述的方式。您将某个类的依赖项传入其构造函数。

  • 字段注入(或 setter 注入)。某些 Android 框架类(如 Activity 和 Fragment)由系统实例化,因此无法进行构造函数注入。使用字段注入时,依赖项将在创建类后实例化。代码如下所示:

class Car {
    lateinit var engine: Engine

    fun start() {
        engine.start()
    }
}

fun main(args: Array) {
    val car = Car()
    car.engine = Engine()
    car.start()
}

四、自动依赖项注入

在上一个示例中,您自行创建、提供并管理不同类的依赖项,而不依赖于库。这称为手动依赖项注入或人工依赖项注入。在 Car 示例中,只有一个依赖项,但依赖项和类越多,手动依赖项注入就越繁琐。手动依赖项注入还会带来多个问题:

  • 对于大型应用,获取所有依赖项并正确连接它们可能需要大量样板代码。在多层架构中,要为顶层创建一个对象,必须提供其下层的所有依赖项。例如,要制造一辆真车,可能需要引擎、传动装置、底盘以及其他部件;而要制造引擎,则需要汽缸和火花塞。

  • 如果您无法在传入依赖项之前构造依赖项(例如,当使用延迟初始化或将对象作用域限定为应用流时),则需要编写并维护管理内存中依赖项生命周期的自定义容器(或依赖关系图)。

有一些库通过自动执行创建和提供依赖项的过程解决此问题。它们归为两类:

  • 基于反射的解决方案,可在运行时连接依赖项。

  • 静态解决方案,可生成在编译时连接依赖项的代码。

Dagger 是适用于 Java、Kotlin 和 Android 的热门依赖项注入库,由 Google 进行维护。Dagger 为您创建和管理依赖关系图,从而便于您在应用中使用 DI。它提供了完全静态和编译时依赖项,解决了基于反射的解决方案(如 Guice)的诸多开发和性能问题。

五、依赖项注入的替代方法

依赖项注入的替代方法是使用服务定位器。服务定位器设计模式还改进了类与具体依赖项的分离。您可以创建一个名为服务定位器的类,该类创建和存储依赖项,然后按需提供这些依赖项。

object ServiceLocator {
    fun getEngine(): Engine = Engine()
}

class Car {
    private val engine = ServiceLocator.getEngine()

    fun start() {
        engine.start()
    }
}

fun main(args: Array) {
    val car = Car()
    car.start()
}

服务定位器模式与依赖项注入在元素使用方式上有所不同。使用服务定位器模式,类可以控制并请求注入对象;使用依赖项注入,应用可以控制并主动注入所需对象。

与依赖项注入相比:

  • 服务定位器所需的依赖项集合使得代码更难测试,因为所有测试都必须与同一全局服务定位器进行交互。

  • 依赖项在类实现中编码,而不是在 API Surface 中编码。因此,很难从外部了解类需要什么。所以,更改 Car 或服务定位器中可用的依赖项可能会导致引用失败,从而导致运行时或测试失败。

  • 如果您想将作用域限定为除了整个应用的生命周期之外的任何区间,就会更难管理对象的生命周期。

六、在 Android 应用中使用 Hilt

Hilt 是推荐用于在 Android 中实现依赖项注入的 Jetpack 库。Hilt 通过为项目中的每个 Android 类提供容器并自动为您管理其生命周期,定义了一种在应用中执行 DI 的标准方法。

Hilt 在热门 DI 库 Dagger 的基础上构建而成,因而能够受益于 Dagger 提供的编译时正确性、运行时性能、可伸缩性和 Android Studio 支持。

如需详细了解 Hilt,请参阅使用 Hilt 实现依赖项注入

七、总结

依赖项注入会为您的应用提供以下优势:

  • 重用类以及分离依赖项:更容易换掉依赖项的实现。由于控制反转,代码重用得以改进,并且类不再控制其依赖项的创建方式,而是支持任何配置。

  • 易于重构:依赖项成为 API Surface 的可验证部分,因此可以在创建对象时或编译时进行检查,而不是作为实现详情隐藏。

  • 易于测试:类不管理其依赖项,因此在测试时,您可以传入不同的实现以测试所有不同用例。

如需充分了解依赖项注入的优势,您应该按照手动依赖项注入中的说明在应用中手动试用。

八、参考链接

  1. Android 中的依赖项注入  |  Android 开发者  |  Android Developers
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hilt 是一个用于简化依赖注入的框架,可以在 Android 应用程序中使用它来管理和注入依赖项。下面是使用 Hilt 进行依赖注入的一个简单示例应用: 1. 添加 Hilt 相关依赖到项目中。在项目的根目录的 `build.gradle` 文件中添加 Hilt Gradle 插件的依赖: ```groovy buildscript { repositories { ... } dependencies { ... classpath 'com.google.dagger:hilt-android-gradle-plugin:<version>' } } ``` 在应用模块的 `build.gradle` 文件中应用 Hilt 插件,并添加 Hilt 相关依赖: ```groovy apply plugin: 'kotlin-kapt' apply plugin: 'dagger.hilt.android.plugin' android { ... } dependencies { implementation 'com.google.dagger:hilt-android:<version>' kapt 'com.google.dagger:hilt-android-compiler:<version>' ... } ``` 2. 在 Application 类上添加 `@HiltAndroidApp` 注解,将其标记为 Hilt 应用程序: ```kotlin import dagger.hilt.android.HiltAndroidApp @HiltAndroidApp class MyApp : Application() { // Application 的实现代码... } ``` 3. 创建一个需要依赖注入的类,例如 UserRepository: ```kotlin import javax.inject.Inject class UserRepository @Inject constructor() { // UserRepository 的实现代码... } ``` 4. 在需要进行依赖注入的类中,使用 `@Inject` 注解来标记需要注入依赖项。例如,在 MainActivity 中: ```kotlin import javax.inject.Inject @AndroidEntryPoint class MainActivity : AppCompatActivity() { @Inject lateinit var userRepository: UserRepository // Activity 的实现代码... } ``` 通过以上步骤,Hilt 会自动管理依赖项的创建和注入。在 MainActivity 中,`userRepository` 字段将会被自动注入一个 UserRepository 实例。 需要注意的是,使用 Hilt 进行依赖注入需要在 Android Studio 中启用 kapt 插件。 这只是一个简单的示例,Hilt 可以在更复杂的应用程序中提供更多的依赖注入功能和灵活性。 希望对你有所帮助!如果还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值