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 生成的组件的层次结构
使用 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
。您还必须使用 @Assisted
为 SavedStateHandle
依赖项添加注释:
class ExampleViewModel @ViewModelInject constructor(
private val repository: ExampleRepository,
@Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {
...
}
然后,带有 @AndroidEntryPoint
注释的 Activity 或 Fragment 可以使用 ViewModelProvider
或 by viewModels()
KTX 扩展照常获取 ViewModel
实例:
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
private val exampleViewModel: ExampleViewModel by viewModels()
...
}