Android Dagger-Hilt 依赖注入
Posted 匆忙拥挤repeat
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Dagger-Hilt 依赖注入相关的知识,希望对你有一定的参考价值。
Author: aa86799@163.com
date: 2020-09-09 00:10
文章目录
- 文档地址
- 依赖配置
- @HiltAndroidApp
- 将依赖项注入 Android 类
- 定义 Hilt 绑定
- Hilt 组件
- 组件层次结构
- 在 Hilt 不默认支持的类中注入依赖项
- 使用 Hilt 注入 ViewModel 对象
- 使用 Hilt 注入 WorkManager
文档地址
https://developer.android.google.cn/training/dependency-injection/hilt-android
依赖配置
project/build.gradle
# 2021-05 hilt已发布正式版,最新版本,直接上hilt官网查看
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
...
compileOptions
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
dependencies
implementation "com.google.dagger:hilt-android:2.28-alpha"
kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
@HiltAndroidApp
@HiltAndroidApp
class ExampleApplication : Application() ...
@HiltAndroidApp
会触发 Hilt 的代码生成操作, 生成的代码包括应用的一个基类,该基类充当应用级依赖项容器
将依赖项注入 Android 类
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() ...
Hilt 目前支持以下 Android 类:
Application
(通过使用@HiltAndroidApp
)Activity
Fragment
View
Service
BroadcastReceiver
(直接用@AndroidEntryPoint注入不成功)- ContentProvider (直接用@AndroidEntryPoint注入不成功)
注意:在 Hilt 对 Android 类的支持方面还要注意以下几点:
- Hilt 仅支持扩展
ComponentActivity
的 Activity,如AppCompatActivity
。- Hilt 仅支持扩展
androidx.Fragment
的 Fragment。- Hilt 不支持保留的 Fragment。
@Inject 注入
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity()
@Inject lateinit var analytics: AnalyticsAdapter
...
定义 Hilt 绑定
向 Hilt 提供绑定信息的一种方法是构造函数注入。在某个类的构造函数中使用 @Inject
注释,以告知 Hilt 如何提供该类的实例:
class AnalyticsAdapter @Inject constructor(
@Inject lateinit var service: AnalyticsService
) ...
在本例中,AnalyticsService
是 AnalyticsAdapter
的一个依赖项。因此,Hilt 还必须知道如何提供 AnalyticsService
的实例。
使用 @Binds 注入接口实例
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
Hilt 模块 AnalyticsModule
带有 @InstallIn(ActivityComponent::class)
注释,因为您希望 Hilt 将该依赖项注入 ExampleActivity
。此注释意味着,AnalyticsModule
中的所有依赖项都可以在应用的所有 Activity 中使用。
使用 @Provides 注入实例
如果某个类不归您所有(因为它来自外部库,如 Retrofit、OkHttpClient
或 Room 数据库等类),或者必须使用构建器模式创建实例,也无法通过构造函数注入。
@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
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AuthInterceptorOkHttpClient
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OtherInterceptorOkHttpClient
方式一
@AuthInterceptorOkHttpClient
@Provides
fun m():OkHttpClient
方式二
@Provides
fun m(@AuthInterceptorOkHttpClient client: OkHttpClient):...
方式三
class ExampleServiceImpl @Inject constructor(
@AuthInterceptorOkHttpClient private val okHttpClient: OkHttpClient
)
方式四
@AuthInterceptorOkHttpClient
@Inject lateinit var okHttpClient: OkHttpClient
与binds结合:(官方文档没写,猜想应该是可以的)
@Binds
@AuthInterceptorOkHttpClient
abstract fun bind(): OkHttpClient
预定义限定符:@ApplicationContext, @ActivityContext
class AnalyticsAdapter @Inject constructor(
@ActivityContext private val context: Context,
private val service: AnalyticsService
) ...
Hilt 组件
@InstallIn
注释中引用相应的组件。限定了注入的实例的生命周期范围。
Hilt 组件 | 注入器面向的对象 |
---|---|
ApplicationComponent | Application |
ActivityRetainedComponent | ViewModel |
ActivityComponent | Activity |
FragmentComponent | Fragment |
ViewComponent | View |
ViewWithFragmentComponent | 带有 @WithFragmentBindings 注释的 View |
ServiceComponent | Service |
组件生命周期
生成的组件 | 创建时机 | 销毁时机 |
---|---|---|
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()
时销毁。
组件作用域
Android 类 | 生成的组件 | 作用域 |
---|---|---|
Application | ApplicationComponent | @Singleton |
View Model | ActivityRetainedComponent | @ActivityRetainedScope |
Activity | ActivityComponent | @ActivityScoped |
Fragment | FragmentComponent | @FragmentScoped |
View | ViewComponent | @ViewScoped |
带有 @WithFragmentBindings 注释的 View | ViewWithFragmentComponent | @ViewScoped |
Service | ServiceComponent | @ServiceScoped |
默认情况下,Hilt 中的所有绑定都未限定作用域。这意味着,每当应用请求绑定时,Hilt 都会创建所需类型的一个新实例。
若限定作用域,如:
@ActivityScoped
class AnalyticsAdapter @Inject constructor(
private val service: AnalyticsService
) ...
@ActivityScoped: Hilt 会在相应 Activity 的整个生命周期内提供 AnalyticsAdapter
的同一实例.
组件层次结构
父组件中绑定的依赖项,对子组件是可见的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xCeJBtzE-1604903187718)(https://developer.android.google.cn/images/training/dependency-injection/hilt-hierarchy.svg)]
注意:默认情况下,如果您在视图中执行字段注入,
ViewComponent
可以使用ActivityComponent
中定义的绑定。如果您还需要使用FragmentComponent
中定义的绑定并且视图是 Fragment 的一部分,应将@WithFragmentBindings
注释和@AndroidEntryPoint
一起使用。
在 Hilt 不默认支持的类中注入依赖项
@EntryPoint 创建入口点。
ContentProvider 不能直接使用 @AndroidEntryPoint ; BroadcastReceiver 也不能。
class ExampleContentProvider : ContentProvider()
@EntryPoint
@InstallIn(ApplicationComponent::class)
interface ExampleContentProviderEntryPoint
fun analyticsService(): AnalyticsService
...
实例:普通类注入 不同的Retrofit(不同的baseUrl) 对象
@EntryPoint
@InstallIn(ApplicationComponent::class)
interface FleetRetrofitProviderEntryPoint
@FleetRetrofit
fun getFleetRetrofit(): Retrofit
//再定义一个不同的 Retrofit baseUrl 的 对象获取函数,不同的 Qualifier
//
val appContext = ExpressApplication.instance().applicationContext
?: throw IllegalStateException()
val networkModule = EntryPointAccessors.fromApplication(appContext, FleetRetrofitProviderEntryPoint::class.java)
val retrofit = networkModule.getFleetRetrofit() //获取相应的Retrofit
val result = retrofit.create(LoginService::class.java).m()...
详情见 fleet项目中的 NetworkModule, LoginBiz
实例:普通类 注入 Repository
@EntryPoint
@InstallIn(ApplicationComponent::class)
interface LocationReceiverEntryPoint
fun repository(): LocationUploadRepository
val entry = EntryPointAccessors.fromApplication(ExpressApplication.instance().applicationContext, LocationReceiverEntryPoint::class.java)
val result = entry.repository().updateLocation(LocationUploadBody(locationItems))
详情见 fleet项目中的 LocationUpdatesBroadcastReceiver
使用 Hilt 注入 ViewModel 对象
app/build.gradle
dependencies
...
implementation 'androidx.hilt:hilt-lifecycle-viewmodel: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() //or activityViewModels()
...
androidx.lifecycle.SavedStateHandle 用于 Activity/Fragment重建时保存变量用的。
- getLiveData(key, [v]): MutableLiveData 获取不到,会内部创建 LiveData; 一个key对应一个LiveData,存放在一个 Map<String, LiveData>中。
- keys(): Set
- set(key, v) 从map中,若取得 LiveData,则liveData.setValue(); 若取不得则存放在 一个Map<String, Object> 中。
- get(key) 从Map<String, Object> 中 get(key)。
使用 Hilt 注入 WorkManager
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'
在 Worker
对象的构造函数中使用 @WorkerInject
注释来注入一个 Worker
。您只能在 Worker
对象中使用 @Singleton
或未限定作用域的绑定。您还必须使用 @Assisted
为 Context
和 WorkerParameters
依赖项添加注释:
class ExampleWorker @WorkerInject constructor(
@Assisted appContext: Context,
@Assisted workerParams: WorkerParameters,
workerDependency: WorkerDependency
) : Worker(appContext, workerParams) ...
然后,让 Application
类实现 Configuration.Provider
接口,注入 HiltWorkFactory
的实例,并将其传入 WorkManager
配置:
@HiltAndroidApp
class ExampleApplication : Application(), Configuration.Provider
@Inject lateinit var workerFactory: HiltWorkerFactory
override fun getWorkManagerConfiguration() =
Configuration.Builder()
.setWorkerFactory(workerFactory)
.build()
以上是关于Android Dagger-Hilt 依赖注入的主要内容,如果未能解决你的问题,请参考以下文章
IOC 控制反转Android 视图依赖注入 ( 视图依赖注入步骤 | 视图依赖注入代码示例 )
IOC 控制反转Android 布局依赖注入 ( 布局依赖注入步骤 | 布局依赖注入代码示例 )
IOC 控制反转Android 事件依赖注入 ( 事件依赖注入代码示例 )