Hilt使用笔记

Hilt是什么

依赖注入框架

优势

  • 重用类以及分离依赖项
    类不再控制其依赖项的创建方式,而是支持任何配置。
  • 易于重构
  • 易于测试
    在测试时,可以传入不同依赖项,测试不同的用例

使用

gradle引用

根目录build.gradle

 buildscript {
         ...
         dependencies {
            ...
           classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
         }
 }

app目录下build.gradle

apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'

android {
    ...
}

dependencies {
      implementation "com.google.dagger:hilt-android:2.28-alpha"
      kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
}

使用注入

所有使用 Hilt 的应用都必须包含一个带有 @HiltAndroidApp 注释的 Application 类。

@HiltAndroidApp 会触发 Hilt 的代码生成操作,生成的代码包括应用的一个基类,该基类充当应用级依赖项容器。

@HiltAndroidApp
class ExampleApplication : Application() { ... }

在 Application 类中设置了 Hilt 且有了应用级组件后,Hilt 可以为带有 @AndroidEntryPoint 注释的其他 Android 类提供依赖项:

Hilt 目前支持以下 Android 类:

  • Application(通过使用 @HiltAndroidApp)
  • Activity 仅支持扩展 ComponentActivity 的 Activity,如 AppCompatActivity
  • Fragment 仅支持扩展 androidx.Fragment 的 Fragment
  • View
  • Service
  • BroadcastReceiver

如果您使用 @AndroidEntryPoint 为某个 Android 类添加注释,则还必须为依赖于该类的 Android 类添加注释。例如,如果您为某个 Fragment 添加注释,则还必须为使用该 Fragment 的所有 Activity 添加注释。

如需从组件获取依赖项,请使用 @Inject 注释执行字段注入:

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}
依赖提供
  • 构造函数法
    在某个类的构造函数中使用 @Inject 注释,以告知 Hilt 如何提供该类的实例:

    class AnalyticsAdapter @Inject constructor(
    private val service: AnalyticsService
    ) { ... }

  • @Binds 注入接口实例
    @Binds 注释会告知 Hilt 在需要提供接口的实例时要使用哪种实现。

带有注释的函数会向 Hilt 提供以下信息:

函数返回类型会告知 Hilt 函数提供哪个接口的实例。
函数参数会告知 Hilt 要提供哪种实现。

interface AnalyticsService {
  fun analyticsMethods()
}

// Constructor-injected, because Hilt needs to know how to
// provide instances of AnalyticsServiceImpl, too.
class AnalyticsServiceImpl @Inject constructor(
  ...
) : AnalyticsService { ... }

@Module
@InstallIn(ActivityComponent::class)
abstract class AnalyticsModule {

  @Binds
  abstract fun bindAnalyticsService(
    analyticsServiceImpl: AnalyticsServiceImpl
  ): AnalyticsService
}
  • @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)
  }
}
  • 为同一类型提供多个绑定

定义注释限定符

@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()
  }
}

使用实例

// 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
}
Hilt组件 注入对象 创建时机 销毁时机 作用域
ApplicationComponent Application Application#onCreate() Application#onDestroy() @Singleton
ActivityRetainedComponent ViewModel Activity#onCreate() Activity#onDestroy() @ActivityRetainedScope
ActivityComponent Activity Activity#onCreate() Activity#onDestroy() @ActivityScoped
FragmentComponent Fragment Fragment#onAttach() Fragment#onDestroy() @FragmentScoped
ViewComponent View View#super() 视图销毁时 @ViewScoped
ViewWithFragmentComponent 带有 @WithFragmentBindings 注释的 View View#super() 视图销毁时 @ViewScoped
ServiceComponent Service Service#onCreate() Service#onDestroy() @ServiceScoped
hilt生成关系.jpg

Hilt 生成的组件的层次结构

使用 Hilt 注入 ViewModel 对象

将下面这些额外的依赖项添加到 Gradle 文件中。请注意,除了库之外,您还需要添加一个额外的注释处理器,它在 Hilt 注释处理器的基础上运行:

app/build.gradle

dependencies {
  ...
  implementation 'androidx.hilt:hilt-work:1.0.0-alpha01'
  // When using Kotlin.
  kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha01'
  // When using Java.
  annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0-alpha01'

}

ViewModel 对象的构造函数中使用 @ViewModelInject 注释来提供一个 ViewModel。您还必须使用 @AssistedSavedStateHandle 依赖项添加注释:

class ExampleViewModel @ViewModelInject constructor(
  private val repository: ExampleRepository,
  @Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {
  ...
}

然后,带有 @AndroidEntryPoint 注释的 Activity 或 Fragment 可以使用 ViewModelProviderby viewModels() KTX 扩展照常获取 ViewModel 实例:

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
  private val exampleViewModel: ExampleViewModel by viewModels()
  ...
}

你可能感兴趣的:(Hilt使用笔记)