Hilt是Google根据Dagger2开发的专用于Android的依靠注入结构,比较Dagger,它的优势如下:
- 简化了Android运用中Dagger相根底架构。
- 创立了一组标准的组件和效果域,以简化设置、提高可读性以及在运用之间共享代码。
- 供给了一种简略的办法来为各种构建类型(如测验、调试或发布)装备不同的绑定。
引入依靠
-
在项目根级
build.gradle
中增加hilt-android-gradle-plugin插件。buildscript { dependencies { classpath 'com.google.dagger:hilt-android-gradle-plugin:x.y.z' } }
-
在模块级
build.gradle
中运用插件和导入依靠。plugins { id 'kotlin-kapt' id 'dagger.hilt.android.plugin' } android { ... // hilt需求敞开Java8 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } } dependencies { implementation "com.google.dagger:hilt-android:2.38.1" kapt "com.google.dagger:hilt-compiler:2.38.1" }
运用
Hilt是在Dagger2的根底上进行开发的,其本质还是对Dagger的运用进行简化。比较dagger- android,Hilt会协助咱们主动生成更多的模板代码,然后让运用过程更加简洁。但不管怎样精简,其Dagger的底层完成还是不变的,因此,了解Dagger将协助咱们更好的掌握Hilt,关于Dagger的介绍拜见Dagger 系列文章。
界说运用类
运用Hilt需求为运用的Application类增加@HiltAndroidApp
注解,运用了此注解后,Hilt将会运用gradle plugin为MyApplication
生成一个名为Hilt_Application
的父类(gradle插件会主动调整MyApplication
的继承)以及运用等级的Component。
@HiltAndroidApp
class MyApplication : Application() {
...
}
在Hilt_Application
中包含着对运用等级Component的初始化代码以及对Application的注入代码:
public abstract class Hilt_MyApplication
extends Application
implements GeneratedComponentManagerHolder
{
private final ApplicationComponentManager componentManager =
new ApplicationComponentManager(new ComponentSupplier() {
@Override
public Object get() {
// 运用等级的Component的初始化
return DaggerMyApplication_HiltComponents_SingletonC.builder()
.applicationContextModule(new ApplicationContextModule(Hilt_MyApplication.this))
.build();
}
});
@Override
public final ApplicationComponentManager componentManager() {
return componentManager;
}
@Override
public final Object generatedComponent() {
return this.componentManager().generatedComponent();
}
@CallSuper
@Override
public void onCreate() {
// 注入
((MyApplication_GeneratedInjector) generatedComponent()).injectMyApplication(UnsafeCasts.<MyApplication>unsafeCast(this));
super.onCreate();
}
}
关于DaggerMyApplication_HiltComponents_SingletonC
的内容将在后文剖析。
为Android其它组件注入依靠
Hilt支撑为以下Android组件注入依靠:
Application
ViewModel
-
ComponentActivity
(不支撑根底的Activity) -
androidx.Fragment
(不支撑根底的Fragment) View
Service
BroadcastReceiver
要为Android组件注入依靠,需求运用@AndroidEntryPoint
注解符号对应的组件类(关于Application
类需求运用@HiltAndroidApp
,关于ViewModel
需求运用@HiltViewModel
),获取依靠项则与Dagger相同,运用@Inject
注解符号非私有字段即可。
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
@Inject lateinit var analytics: AnalyticsAdapter
...
}
与@HiltAndroidApp
相同,Hilt也会为@AndroidEntryPoint
和@HiltViewModel
符号的组件生成相应的Component和用于完成注入的父类。
绑定(依靠供给)
Hilt中的绑定与Dagger中的界说方式共同。
关于咱们能够操控的依靠类型,直接在结构函数上运用@Inject
注解即可。
class Student @Inject constructor() {
...
}
关于无法运用constructor-inject
的依靠类型,也能够运用模块供给绑定信息。Hilt的模块和Dagger的模块是相同的,也是运用@Module
符号的类。但需求注意的是,在Hilt中需求运用@InstallIn
为模块指定要安装到的Component,关于Component的介绍见后文组件 Component 。
@Module
@InstallIn(SingletonComponent::class)
class CommonModule {
...
}
和Dagger相同,在模块中,咱们能够运用@Provides
以及@Binds
系列的注解来绑定依靠项。
@Module
@InstallIn(SingletonComponent::class)
class CommonModule {
@Provides
fun provideSp(
context: Application
): SharedPreferences {
return context.getSharedPreferences("main", Context.MODE_PRIVATE)
}
@Binds
abstract fun bindAnalyticsService(
analyticsServiceImpl: AnalyticsServiceImpl
): AnalyticsService
...
}
限制符 Qualifier
Hilt中限制符的运用也与Dagger中相同。可是Hilt为Android供给了两个预界说的限制符:@ApplicationContext
与@ActivityContext
,用来限制注入的context是运用的context还是Activity的context。
组件 Component
运用Hilt时,大部分时分咱们都无需手动界说Component,Hilt会主动的帮咱们生成与Android组件相应的Component。Hilt供给了以下组件的主动生成:
Android 组件 | Hilt Component |
---|---|
Application | SingletonComponent |
– | ActivityRetainedComponent |
ViewModel | ViewModelComponent |
Activity | ActivityComponent |
Fragment | FragmentComponent |
View | ViewComponent |
运用@WithFragmentBindings符号的View | ViewWithFragmentComponent |
Service | ServiceComponent |
Hilt不会为
BroadcastReceiver
生成组件,BroadcastReceiver
直接经过SingletonComponent
履行注入。
Hilt也允许你自界说Component,可是大部分时分都不需求它,关于自界说Component能够参考官方文档。
组件的层次结构
Hilt会将生成的Component组织成一定的层次结构,在这个层次结构中,位于下面的组件能够直接运用上层的子组件的依靠项,比方ViewComponent
能够运用ActivityComponent
中的依靠项;ActivityComponent
能够运用SingletonComponent
中的依靠项。
组件的生命周期
Hilt会按照对应Android组件类的生命周期主动创立和毁掉生成Component实例。
Component | 创立机遇 | 毁掉机遇 |
---|---|---|
SingletonComponent | Application#onCreate() | Application#已毁掉 |
ActivityRetainedComponent | Activity#onCreate() | Activity#onDestroy() |
ViewModelComponent | ViewModel已创立 | ViewModel已毁掉 |
ActivityComponent | Activity#onCreate() | Activity#onDestroy() |
FragmentComponent | Fragment#attach() | Fragment#onDestroy() |
ViewComponent | View#super() | View已毁掉 |
ViewWithFragmentComponent | View#super() | View已毁掉 |
ServiceComponent | Service#onCreate() | Service#onDestroy() |
比较
ActivityComponent
,ActivityRetainedComponent
在运用装备更改(如反正屏)引起Activity重建后依然存在。
❓ Q:
ActivityRetainedComponent
与ActivityComponent
创立和毁掉机遇共同,为何ActivityRetainedComponent
能够在装备更改后仍然存在,ActivityComponent
则不可?
A:ActivityRetainedComponentManager
会创立ActivityRetainedComponentViewModel
,然后把ActivityRetainedComponent
的实例存储在其间,ActivityRetainedComponentViewModel
实例则经过ViewModelStore保存到Activity中。换句话说,其实就是借用了ViewModel的重建保存才能。
Component的默许绑定
Hilt会为生成的Component供给一些默许绑定,比方关于SingletonComponent
,Hilt会为其默许绑定Application实例,关于ActivityComponent
,Hilt则会为其默许绑定对应Activity的实例。除此之外,由于Hilt中Component的层次联系,Component也能够拜访到SubComponent供给的默许绑定。比方ActivityComponent
也能够拜访到SingletonComponent
中的Application实例。
下表给出了各种Component能够拜访到的默许绑定依靠项:
Component | 默许绑定依靠项 |
---|---|
SingletonComponent | Application |
ActivityRetainedComponent | Application |
ViewModelComponent | SavedStateHandle |
ActivityComponent | Application、Activity |
FragmentComponent | Application、Activity、Fragment |
ViewComponent | Application、Activity、View |
ViewWithFragmentComponent | Application、Activity、Fragment、View |
ServiceComponent | Application、Service |
效果域
Hilt中效果域的运用也与Dagger中相同。相同的Hilt也为生成的Component供给了预置的效果域注解,用于将依靠项实例的生命周期限制在对应Component的生命周期中:
Component | 效果域 |
---|---|
SingletonComponent | @Singleton |
ActivityRetainedComponent | @ActivityRetainedScoped |
ViewModelComponent | @ViewModelScoped |
ActivityComponent | @ActivityScoped |
FragmentComponent | @FragmentScoped |
ViewComponent | @ViewScoped |
ViewWithFragmentComponent | @ViewScoped |
ServiceComponent | @ServiceScoped |
在Hilt不支撑的类中完成注入
Dagger中,咱们能够在Component中编写返回依靠项实例的接口来对外露出依靠图中的依靠项。
@Component(modules = [CommonModule::class])
interface AppComponent {
fun inject(application: Application)
fun exposeSharedPreference(): SharedPreference
}
class MyClassCannotBeInject {
fun test(component: AppComponent) {
val sp = component.exposeSharedPreference()
...
}
}
但在Hilt中由于Component是主动生成的,咱们无法直接为其编写露出依靠项的接口。为此Hilt供给了@EntryPoint
注解,@EntryPoint
能够界说一个进口点,其它Hilt不支撑办理的类能够经过进口点拜访依靠图中的依靠项。@EntryPoint
需求配合@InstallIn
一同运用,标明要附加到哪个Component上。
@EntryPoint
@InstallIn(SingletonComponent::class)
interface ExampleEntryPoint {
fun sharedPreference(): SharedPreference
}
界说了进口点后,咱们就能够运用EntryPointAccessors
中适当的静态办法获取拜访点。比方咱们的拜访点安装在SingletonComponent
上,就需求运用fromApplication
办法。
EntryPointAccessors.fromApplication(appContext,
ExampleEntryPoint::class.java)
val sp = hiltEntryPoint.sharedPreference()
完成原理
Hilt的拜访点在完成上实际上是在生成Component时,将@EntryPoint
符号的接口作为其父接口继承其间露出的接口办法。
@Component(
modules = {
ApplicationContextModule.class,
CommonModule.class,
ActivityRetainedCBuilderModule.class,
ServiceCBuilderModule.class
}
)
@Singleton
public abstract static class SingletonC implements
HiltWrapper_ActivityRetainedComponentManager_ActivityRetainedComponentBuilderEntryPoint,
ServiceComponentManager.ServiceComponentBuilderEntryPoint,
SingletonComponent,
GeneratedComponent,
MyApplication_GeneratedInjector,
ExampleEntryPoint { }
public final class DaggerMyApplication_HiltComponents_SingletonC
extends MyApplication_HiltComponents.SingletonC {
...
@Override
public SharedPreference sharedPreference() {
return provideSharedPreferenceProvider.get();
}
}
资料
-
Google官方运用指引
运用 Hilt 完成依靠项注入 | Android 开发者 | Android Developers