JetPack系列之Hilt使用

1、基本介绍:

  • 字段注入:Hilt 需要知道如何从相应组件Component中提供必要依赖项的实例。
  • 绑定:将某个类型的实例作为依赖项提供所需的信息。

2、注解:

@HiltAndroidApp:

  • 所有使用 Hilt 的应用都必须包含一个带有 @HiltAndroidApp 注释的 Application 类。
  • @HiltAndroidApp 会触发 Hilt 的代码生成操作,生成的代码包括应用的一个基类,该基类充当应用级依赖项容器。
  • 生成的这一 Hilt 组件会附加到 Application 对象的生命周期,并为其提供依赖项。
  • 此外,它也是应用的父组件,这意味着,其他组件可以访问它提供的依赖项。
@HiltAndroidApp
class MyApplication:Application() { }
复制代码

@AndroidEntryPoint:

  • 在 Application 类中设置了 Hilt 且有了应用级组件后,@AndroidEntryPoint 会为项目中的每个 Android 类(Activity、Fragment、Service、View、BroadcastReceiver)生成一个单独的 Hilt 组件Component。这些组件可以从它们各自的父类接收依赖项。
  • 如果您使用 @AndroidEntryPoint 为某个 Android 类添加注释,则还必须为依赖于该类的 Android 类添加注释。例如,如果您为某个 Fragment 添加注释,则还必须为使用该 Fragment 的所有 Activity 添加注释。
  • Hilt 仅支持扩展 ComponentActivity 的 Activity,如 AppCompatActivity。
  • Hilt 仅支持扩展 androidx.Fragment 的 Fragment。

@Inject:

  • 由 Hilt 注入的字段不能为私有字段。
  • 用在属性字段上或者构造函数上,用于注入字段或者提供构造类实例。

@InstallIn:

  • 声明当 Hilt 生成Component时(比如ActivityComponent是自动生成的),被注解标识的目标类应该被包含在哪些Component中。
  • 只能用于有@Module、@EntryPoint注释的类中。
@Module
@InstallIn(ActivityComponent::class)  //告诉Hilt 这个module属于的Component,ActivityComponent是Hilt定义好的
interface MainModule {
    @Binds
    fun bindEngine(chinaEngine:ChinaEngine):Engine
}
复制代码

3、Hilt中的组件Component:

3.1、基本介绍:

  • 对于可以从中执行字段注入的每个 Android 类(Activity、Fragment、Service、View、BroadcastReceiver),都需要有一个关联的 Hilt 组件,您可以用 @InstallIn 注解引用该组件。
  • 每个 Hilt 组件负责将其绑定注入相应的 Android 目标类(@Inject注解使用的目标类Activity、Fragment、Service、View、BroadcastReceiver)。

3.2、Hilt默认提供的组件:

Hilt 组件 注入器面向的对象
ApplicationComponent Application
ActivityRetainedComponent ViewModel
ActivityComponent Activity
FragmentComponent Fragment
ViewComponent View
ViewWithFragmentComponent 带有 @WithFragmentBindings 注释的 View
ServiceComponent Service
  • Hilt 不会为广播接收器生成组件,因为 Hilt 直接从 ApplicationComponent 注入广播接收器。

3.3、组件的默认生命周期:

生成的组件 创建时机 销毁时机
ApplicationComponent Application#onCreate() Application#onDestroy()
ActivityRetainedComponent Activity#onCreate() Activity#onDestroy()
ActivityComponent Activity#onCreate() Activity#onDestroy()
FragmentComponent Fragment#onAttach() Fragment#onDestroy()
ViewComponent View#super() 视图销毁时
ViewWithFragmentComponent View#super() 视图销毁时
ServiceComponent Service#onCreate() Service#onDestroy()
  • ActivityRetainedComponent 在配置更改后仍然存在,因此它在第一次调用 Activity#onCreate() 时创建,在最后一次调用 Activity#onDestroy() 时销毁。

3.4、组件的作用域:

  • 默认情况下,Hilt 中的所有绑定都未限定作用域。这意味着,每当应用请求绑定时,Hilt 都会创建所需类型的一个新实例。
  • 将绑定的作用域限定为某个组件的成本可能很高,因为提供的对象在该组件被销毁之前一直保留在内存中共存一份实例。请在应用中尽量少用限定作用域的绑定。
  • 如果绑定的内部状态要求在某一作用域内使用同一实例,或者绑定的创建成本很高,那么将绑定的作用域限定为某个组件是一种恰当的做法。
Android 类 生成的组件 作用域
Application ApplicationComponent @Singleton
View Model ActivityRetainedComponent @ActivityRetainedScope
Activity ActivityComponent @ActivityScoped
Fragment FragmentComponent @FragmentScoped
View ViewComponent @ViewScoped
带有 @WithFragmentBindings 注释的 View ViewWithFragmentComponent @ViewScoped
Service ServiceComponent @ServiceScoped

3.5、组件的层次依赖结构关系:

  • 将模块Module安装到组件后,该Module中的绑定提供就可以用作该组件中其他绑定的依赖项,也可以用作组件层次结构中该组件下的任何子组件中其他绑定的依赖项。
    在这里插入图片描述

3.6、组件默认提供的绑定实例:

  • 每个 Hilt 组件都附带一组默认绑定实例,Hilt 可以将其作为依赖项注入您自己的自定义绑定。
  • 请注意,这些绑定对应于常规 Activity 和 Fragment 类型,而不对应于任何特定子类。这是因为,Hilt 会使用单个 Activity 组件定义来注入所有 Activity。每个 Activity 都有此组件的不同实例。
Android 组件 默认绑定
ApplicationComponent Application
ActivityRetainedComponent Application
ActivityComponent Application 和 Activity
FragmentComponent Application、Activity 和 Fragment
ViewComponent Application、Activity 和 View
ViewWithFragmentComponent Application、Activity、Fragment 和 View
ServiceComponent Application 和 Service

4、Hilt中的模块Module:

  • 有时,类型不能通过构造函数注入,在这些情况下,您可以使用 Hilt 模块向 Hilt 提供绑定信息。
  • Hilt 模块是一个带有 @Module 注释的类。与 Dagger 模块一样,它会告知 Hilt 如何提供某些类型的实例。
  • 您必须使用 @InstallIn 为 Hilt 模块添加注释,以告知 Hilt 每个模块将用在或安装在哪个 Android 类中。
  • Module其他使用跟Dagger2用法一样,具体见下一篇Dagger2使用。

5、在Hilt默认不支持的类中提供依赖注入:

  • 因为@AndroidEntryPoint 使用范围有限,在这范围之外要使用Hilt 注入的实例就可以使用@EntryPoint 来实现。
  • 这个像是Hilt 把Component标准化后,使用者不能再里面添加方法,导致不能为使用不了注解的地方提供依赖而做出的解决方案。
  • @EntryPoint
    • 用于标记一个接口作为生成组件Component的入口点。
    • 这个注解必须跟@InstallIn一起使用,以表明哪个(些)组件Component应该有这个入口点。
    • Hilt会让指定的组件 extend 这个注解标记的接口。
  //让SingletonComponent组件绑定Bar实例。
  @EntryPoint
  @InstallIn(SingletonComponent.class)
  public interface FooBarInterface {
    Bar getBar();
  }
   
  //从SingletonComponent组件中获取绑定的Bar实例
  Bar bar = EntryPoints.get(applicationContext, FooBarInterface.class).getBar();
复制代码

6、在多模块应用中使用 Hilt:

  • Hilt 代码生成操作需要访问使用 Hilt 的所有 Gradle 模块。编译 Application 类的 Gradle 模块需要在其传递依赖项中包含所有 Hilt 模块和通过构造函数注入的类。
  • 如果多模块项目由常规 Gradle 模块组成,则您可以按照使用 Hilt 实现依赖项注入中的说明使用 Hilt。不过,对于包含动态功能模块 (DFM) 的应用,并不是这样。
  • 在 DFM 中,通常模块之间相互依赖的方式颠倒过来。因此,Hilt 无法在动态功能模块中处理注释。您必须在 DFM 中使用 Dagger 执行依赖项注入。
  • 您必须使用组件依赖关系来解决 DFM 的这一问题。请按以下步骤操作:
    • 在具有 DFM 所需依赖项的 app 模块(或可由 Hilt 处理的其他任何模块)中声明一个 @EntryPoint 接口。
    • 在DFM模块中创建一个依赖于 @EntryPoint 接口的 Dagger Component组件。
    • 在 DFM 模块中照常使用 Dagger2。

参考:dagger.dev/hilt/quick-…


了解更多,欢迎关注:

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享