基本概念
- 用 @EntryPoint 表示当前类需要被注入
- 用 @XXXComponent 表示其作用范围域,InstallIn,就是安装到的意思。那么@InstallIn(ActivityComponent::class),就是把这个模块安装到Activity组件当中。既然是安装到了Activity组件当中,那么自然在Activity中是可以使用由这个模块提供的所有依赖注入实例。另外,Activity中包含的Fragment和View也可以使用,但是除了Activity、Fragment、View之外的其他地方就无法使用了。
- @module 表示这是一个用于提供依赖注入实例的模块 @Bind 表示可提供依赖 @Provides 表示提供依赖
- @Qualifier注解的作用就是专门用于解决我们目前碰到的问题,给相同类型的类或接口注入不同的实例
- 如果两个 activity 用不同的实例呢?
- Component,从 Hilt 找依赖 然后注入给 需求依赖的地方。 将 @module 中提供的实例 传递给 @inject 标记的变量。
使用步骤
- Application 声明 @HiltAndroidApp,
- Android Class 声明 @AndroidEntryPoint, 如果非 Android Class , 声明 @EntryPoint。告诉hilt 当前类的被 @inject的变量需要被注入实例。
- hilt 看着 @inject 标注的变量, 去找其声明,如果其 构造函数有 @inject 就调用构造函数返回, 如果没有构造函数被 @inject , 就找@Module
- 每个 module 通过 @InstallIn 表示当前module能够给哪些 Classes 提供实例。 比如 SingletonComponent,就是全局class都从 这里取实例
- @Qualifier 告诉hilt, 如果 module 中有可以提供多个接口的实例,可以通过不同的 @Qualifier 取。
- 比如下面的例子就表示,创建 okhttpclient 需要 @InterceptorBASIC对应的实例。比如下面的例子就表示,创建 okhttpclient 需要 @InterceptorBASIC 对应的Interceptor实例。
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import javax.inject.Qualifier
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class InterceptorBASIC
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class InterceptorHEADERS
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
fun provideLogInterceptorOkHttpClient(
@InterceptorHEADERS loggingInterceptor: Interceptor
): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()
}
@Provides
@InterceptorHEADERS
fun provideLogInterceptorBASIC(): Interceptor {
return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC)
}
@Provides
@InterceptorBASIC
fun provideLogInterceptorHEADERS(): Interceptor {
return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.HEADERS)
}
}
复制代码
- viewModel 以及其成员变量不能持有 activity context
对一些概念说明一下
- @HiltAndroidApp // 启动 hilt 工作, 创建 applicationComponent, 让 hilt 能够给项目中的所有类提供依赖。
@HiltAndroidApp
class ExampleApplication : Application() { … }
- @inject 注入依赖,通过标记,表示其需要被注入依赖。
- @HiltAndroidApp 标记在application 当前应用需要依赖
- @AndroidEntryPoint 标记在四大组件(activity、service) 、Fragment、view 表示其需要依赖, 注意, 使用 @AndroidEntryPoint ,需要保证其依赖的所有class也都使用了此注解, 比如 Fragment如果使用@AndroidEntryPoint, 那么其 activity 也需要@AndroidEntryPoint。
- @HiltViewModel
@AndroidEntryPoint 会为每一个 Android Class 生成 component, component会接受依赖,而且具有传递性,具体见 Component hierarchy.
接着, 通过 @AndroidEntryPoint表示当前类需要注入, 然后通过 @Inject 给变量表示当前变量需要被注入实例。
Note: 1. Fields injected by Hilt cannot be private. Attempting to inject a private field with Hilt results in a compilation error.
3. 如果 hilt 提供的实例, 需要依赖其他实例,就需要Define Hilt bindings, 具体没讲,后面补充
class AnalyticsAdapter @Inject constructor(
private val service: AnalyticsService
) { ... }
复制代码
- Hilt module
如果需要一个接口实现,或者三方库,我们不能在其构造函数中 @inject , 就需要通过 @module 组织后提供给 hilt。
1. 通过 @bind 提供接口实例。 比如上面的 AnalyticsService 是一个接口, 我们就可以 @module 标记的类中 提供一个抽象方法,具体如下
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
}
复制代码
- bindAnalyticsService return type tells Hilt what interface the function provides instances of.
- bindAnalyticsService parameter tells Hilt which implementation to provide.
2. module 上的 @InstallIn(ActivityComponent::class) ,表示module中提供的所有实例能被项目中所有 activity 使用。
3. 通过 @Provides 提供三方库的实例。
@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, 比如下面在 @provide 上面注解 @InterceptorBASIC 和 @InterceptorHEADERS 标记提供的不同实例, 在需要此实例的变量前使用不同的注解,表示需要不同的实例, 比如下面的例子就表示,创建 okhttpclient 需要 @InterceptorBASIC对应的实例。
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import javax.inject.Qualifier
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class InterceptorBASIC
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class InterceptorHEADERS
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
fun provideLogInterceptorOkHttpClient(
@InterceptorHEADERS loggingInterceptor: Interceptor
): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()
}
@Provides
@InterceptorHEADERS
fun provideLogInterceptorBASIC(): Interceptor {
return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC)
}
@Provides
@InterceptorBASIC
fun provideLogInterceptorHEADERS(): Interceptor {
return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.HEADERS)
}
}
复制代码
- 预制的 qualifers
Hilt 通过 @ApplicationContext 和 @ActivityContext 提供不同的实例, 比如下面的例子就表示 AnalyticsAdapter 需要 hilt 提供 activity 的 context。
class AnalyticsAdapter @Inject constructor(
@ActivityContext private val context: Context,
private val service: AnalyticsService
) { ... }
复制代码
- @InstallIn()
我们前面已经知道 Component 表示当前类需要被注入, 那Component 是怎么拿到实例的呢? 开发者 通过在 module上使用 @InstallIn 告诉 hilt, module 提供的这些实例可以被哪种
8.预制 qualifers
常见错误
- 如果被 @inject 的变量有基类, 不需要给基类声明 @AndroidEntryPoint
- Without an @inject constructor or an…..
使用不当造成的,比如
- viewmodel 中持有 context.
原因:
A module scoped to the ViewModelComponent cannot provide @ActivityContext Context because that would be a leak since ViewModels are retained across configuration changes and outlive the Activity. However if you only need a Context, not necessarily the activity one, then you can change your provider function to request for a Context with the @ApplicationContext qualifier.
- Module 提供的实例,比 @InstallIn 的生命周期长, 比如如下代码.
@Module
@InstallIn(SingletonComponent::class)
class TestModule {
@Provides
@Singleton
fun provideTestSingleton(): TestSingleton {
Log.d("heiheihei", "ApplicationModule provideTestSingleton")
return TestSingleton()
}
}
复制代码
上面的代码 提供 的 TestSingleton 实例是在 activity 中使用的, 如果我将 SingletonComponent 改成 ViewComponent 就会复现上面的问题, 由此说明上面的bug,就是由于 提供的 context 的module 作用域的问题。
作用域该怎么应对, 如下:

比如 singletonComponet 的 module 可以给箭头指向的所有 component 提供实例。 但是 viewComponet 就只有它自己能获得实例。


















![[02/27][官改] Simplicity@MIX2 ROM更新-一一网](https://www.proyy.com/wp-content/uploads/2020/02/3168457341.jpg)


![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)