Hilt是什么?
Hilt是Google工程师找到Dagger2团队专门为Android定制的依赖注入框架,相对于Dagger2,Hilt使用起来更加简单,不需要创建各种Component类;使用依赖注入框架可以让我们的对代码进行解耦,减少代码量的编写。
基本使用
项目配置
-
配置Hilt gradle插件
buildscript { ... dependencies { ... classpath 'com.google.dagger:hilt-android-gradle-plugin:2.37' } }
-
配置App/build.gradle:之所以要指定java8是因为Hilt使用到了java8中的一些特性
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.37' kapt 'com.google.dagger:hilt-android-compiler:2.37' }
-
在自定义Application上加上
@HiltAndroidApp
注解@HiltAndroidApp class MyApplication : Application() { }
注入简单对象
-
创建User类,并在构造方法中加上
@Inject
注解class User @Inject constructor() { }
-
在需要注入的类中加上
@AndroidEntryPoint
注解@AndroidEntryPoint class HiltActivity : AppCompatActivity() { }
-
在需要依赖注入的变量上加上
@Inject
注解;需要注意的是依赖注入的变量不能是private
@AndroidEntryPoint class HiltActivity : AppCompatActivity() { @Inject lateinit var mUser: User }
-
如果需要全局单例,则只需要在User对象上加上
@Singleton
注解@Singleton class User @Inject constructor() { }
第三方库中的对象注入
-
如果需要注入的对象是第三方库中的,我们无法修改它的源码,则需要通过创建Module类提供创建对象的方法;例如需要依赖注入ARouter对象
@InstallIn(ActivityComponent::class) @Module class ARouterModule { @Provides fun providerARouter(): ARouter = ARouter.getInstance() } @AndroidEntryPoint class HiltActivity : AppCompatActivity() { @Inject lateinit var mARouter: ARouter }
-
对第三方对象注入使用单例模式;需要修改Module类,
@InstallIn(ActivityComponent::class)
改成@InstallIn(SingletonComponent::class)
(低版本Hilt中叫ApplicationComponent
);然后在创建对象的方法上加上@Singleton
注解@InstallIn(SingletonComponent::class) @Module class ARouterModule { @Singleton @Provides fun providerARouter(): ARouter = ARouter.getInstance() }
带参数的对象注入
-
假如User依赖Car对象,只需要在Car类构造方法添加
@inject
注解,以告诉Hilt如何创建这个对象即可class Car @Inject constructor() { } class User @Inject constructor(val car: Car) { fun printInfo(){ Log.i("testHilt","user=$this => car=$car") } }
-
注入Context:如果某个对象的创建依赖Context,只需要加上
@ApplicationContext
(注入Application)或者@ActivityContext
(注入当前变量所在Activity)即可;也可以不加注解,把依赖的对象改成Application
或者Activity
也是一样的效果- 使用注解方式
class User @Inject constructor(@ActivityContext val context: Context) { fun printInfo(){ Log.i("testHilt","context=$context") } } class User @Inject constructor(@ApplicationContext val context: Context) { fun printInfo(){ Log.i("testHilt","context=$context") } }
- 使用
Application
或者Activity
方式class User @Inject constructor(val context: Application) { fun printInfo(){ Log.i("testHilt","context=$context") } } class User @Inject constructor(val context: Activity) { fun printInfo(){ Log.i("testHilt","context=$context") } }
- 使用注解方式
接口注入
-
为接口类型变量注入实现类,先创建一个接口
interface IAction { fun doAction() }
-
创建两个实现类,并在构造方法上加上
@Inject
以便Hilt可以通过它构建对象class RunAction @Inject constructor() : IAction { override fun doAction() { Log.i("testDagger","RunAction") } } class SitAction @Inject constructor() :IAction { override fun doAction() { Log.i("testDagger","SitAction") } }
-
由于注入对象时,需要注入的是接口实现,返回的对象类型也是接口,为了区分不同方法创建不同对象实现,需要定义两个不同的自定义注解
BindRunAction
BindSitAction
名字可以随便取@Qualifier @Retention(AnnotationRetention.RUNTIME) @Target( AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.PROPERTY ) annotation class BindRunAction
@Qualifier @Retention(AnnotationRetention.RUNTIME) @Target( AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.PROPERTY ) annotation class BindSitAction
-
创建Module类提供接口实列的创建
@InstallIn(ActivityComponent::class) @Module abstract class ActionModule { @BindRunAction @Binds abstract fun bindRunAction(runAction: RunAction): IAction @BindSitAction @Binds abstract fun bindSitAction(runAction: SitAction): IAction }
-
依赖注入接口实现对象,根据需要添加不同注解以实现注入不同接口实现类
@AndroidEntryPoint class HiltActivity : AppCompatActivity() { @BindRunAction @Inject lateinit var mRunAction: IAction @BindSitAction @Inject lateinit var mSitAction: IAction }