文章目录
一、前言
Hilt
是对Dagger
的封装处理,这里对其进行下简单介绍。
二、添加依赖
implementation 'com.google.dagger:dagger:2.41'
kapt 'com.google.dagger:dagger-compiler:2.41'
三、简单示例
class UserRepository @Inject constructor(
private val localDataSource: UserLocalDataSource,
private val remoteDataSource: UserRemoteDataSource
) {
fun printUserName(){
localDataSource.printUserName()
}
}
// @Inject lets Dagger know how to create instances of these objects
class UserLocalDataSource @Inject constructor() {
fun printUserName(){
Log.e("YM--->","---获取用户姓名")
}
}
class UserRemoteDataSource @Inject constructor() { }
@Component
interface ApplicationGraph {
// The return type of functions inside the component interface is
// what can be provided from the container
fun repository(): UserRepository
}
class DaggerActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dagger)
// Create an instance of the application graph
val applicationGraph: ApplicationGraph = DaggerApplicationGraph.create()
// Grab an instance of UserRepository from the application graph
val userRepository: UserRepository = applicationGraph.repository()
userRepository.printUserName()
}
}
需要注意的是,写完后需要重新build下才能生成DaggerApplicationGraph
类。另外需要注意的是Dagger 在每次收到请求时都会创建 UserRepository 的新实例。所以以下两种实例对象不是一个对象
val applicationGraph: ApplicationGraph = DaggerApplicationGraph.create()
val userRepository: UserRepository = applicationGraph.repository()
val userRepository2: UserRepository = applicationGraph.repository()
assert(userRepository != userRepository2)
如果要是需要多个依赖项目共用一个实例的话,需要引入作用域的概念
四、作用域
修改代码为如下
@Singleton
class UserRepository @Inject constructor(
private val localDataSource: UserLocalDataSource,
private val remoteDataSource: UserRemoteDataSource
) {
fun printUserName(){
localDataSource.printUserName()
}
}
@Singleton
@Component
interface ApplicationGraph {
// The return type of functions inside the component interface is
// what can be provided from the container
fun repository(): UserRepository
}
五、自定义作用域
暂时不知道自定义作用域的目的,这里仅仅做个记录
将代码修改为以下可以实现同一目的
@Scope
@MustBeDocumented
@Retention(value = AnnotationRetention.RUNTIME)
annotation class MyCustomScope
@MyCustomScope
@Component
interface ApplicationGraph {
// The return type of functions inside the component interface is
// what can be provided from the container
fun repository(): UserRepository
}
@MyCustomScope
//@Singleton
class UserRepository @Inject constructor(
private val localDataSource: UserLocalDataSource,
private val remoteDataSource: UserRemoteDataSource
) {
fun printUserName(){
localDataSource.printUserName()
}
}
六、@Binds 和 @Provides
dagger
的使用和Hilt
的用法一直,这里不再记录,详情参考Hilt
一章
七、关于Dagger为什么在Android中要比Hilt复杂
为什么Dagger在Android中会比Hilt
用起来复杂?这是因为通常来说,Dagger
生成对象需要通过构造函数来生成,但是由于某些 Android 框架类(如 Activity 和 Fragment)由系统实例化,因此 Dagger 无法为您创建这些类。因此生成起来就比较麻烦的多。所以对于这些类必须使用字段注入。举个例子,假设我们想在一个类里面使用Activit
对象,我们是没有办法通过构造函数的方式生成这个对象的,比如如下代码
@Inject lateinit var act: Activity
虽然定义了Activity,但是却没有办法去生成它。
详情参考dagger官网
八、inject(Activity act)的用法
通常的方式是通过一个 inject()函数进行绑定,代码如下
class UserViewModel @Inject constructor(){
fun test(){
Log.e("YM","======")
}
}
@Component
interface UserComponent{
fun inject(activity: DaggerActivity)
}
class DaggerActivity : AppCompatActivity() {
@Inject lateinit var useViewModel: UserViewModel
override fun onCreate(savedInstanceState: Bundle?) {
DaggerUserComponent.create().inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
useViewModel.test()
}
}
如果不使用fun inject(activity: DaggerActivity)
进行绑定,那么使用useViewModel
时候就会出现未初始化的问题。这里可以查看下一个生成的代码
@DaggerGenerated
@SuppressWarnings({
"unchecked",
"rawtypes"
})
public final class DaggerUserComponent implements UserComponent {
private final DaggerUserComponent userComponent = this;
private DaggerUserComponent() {
}
public static Builder builder() {
return new Builder();
}
public static UserComponent create() {
return new Builder().build();
}
@Override
public void inject(DaggerActivity activity) {
injectDaggerActivity(activity);
}
private DaggerActivity injectDaggerActivity(DaggerActivity instance) {
DaggerActivity_MembersInjector.injectUseViewModel(instance, new UserViewModel());
return instance;
}
public static final class Builder {
private Builder() {
}
public UserComponent build() {
return new DaggerUserComponent();
}
}
}
@QualifierMetadata
@DaggerGenerated
@SuppressWarnings({
"unchecked",
"rawtypes"
})
public final class DaggerActivity_MembersInjector implements MembersInjector<DaggerActivity> {
private final Provider<UserViewModel> useViewModelProvider;
public DaggerActivity_MembersInjector(Provider<UserViewModel> useViewModelProvider) {
this.useViewModelProvider = useViewModelProvider;
}
public static MembersInjector<DaggerActivity> create(
Provider<UserViewModel> useViewModelProvider) {
return new DaggerActivity_MembersInjector(useViewModelProvider);
}
@Override
public void injectMembers(DaggerActivity instance) {
injectUseViewModel(instance, useViewModelProvider.get());
}
@InjectedFieldSignature("com.dagger.application.dagger.DaggerActivity.useViewModel")
public static void injectUseViewModel(DaggerActivity instance, UserViewModel useViewModel) {
instance.useViewModel = useViewModel;
}
}
通过生成的代码可以看出是关联过程的。
九、作用域和子组件
这一章节不算复杂,这里将代码贴出作为记录
// @Inject lets Dagger know how to create instances of this object
@Singleton
class UserRepository @Inject constructor(
private val localDataSource: UserLocalDataSource,
private val remoteDataSource: UserRemoteDataSource
) {
fun printUserName(){
// localDataSource.printUserName()
remoteDataSource.printUserName()
}
}
// @Inject lets Dagger know how to create instances of these objects
class UserLocalDataSource @Inject constructor() {
fun printUserName(){
Log.e("YM--->","---获取用户姓名")
}
}
class UserRemoteDataSource @Inject constructor( private val loginService: LoginRetrofitService) {
fun printUserName(){
Log.e("YM--->","---remote")
}
}
class LoginRetrofitService @Inject constructor(){
}
@Module
class NetworkModule {
// @Provides tell Dagger how to create instances of the type that this function
// returns (i.e. LoginRetrofitService).
// Function parameters are the dependencies of this type.
@Provides
fun provideLoginRetrofitService(): LoginRetrofitService {
// Whenever Dagger needs to provide an instance of type LoginRetrofitService,
// this code (the one inside the @Provides method) is run.
return LoginRetrofitService()
}
}
// The "subcomponents" attribute in the @Module annotation tells Dagger what
// Subcomponents are children of the Component this module is included in.
@Module(subcomponents = [LoginComponent::class])
class SubcomponentsModule {}
@ActivityScope
class LoginViewModel @Inject constructor(private val userRepository: UserRepository) {
fun toast(){
Log.e("YM","======")
}
}
@Singleton
@Component(modules = [NetworkModule::class, SubcomponentsModule::class])
interface ApplicationGraph {
// The return type of functions inside the component interface is
// what can be provided from the container
fun repository(): UserRepository
// fun inject(activity: Application)
// This function exposes the LoginComponent Factory out of the graph so consumers
// can use it to obtain new instances of LoginComponent
fun loginComponent(): LoginComponent.Factory
}
// Definition of a custom scope called ActivityScope
@Scope
@Retention(value = AnnotationRetention.RUNTIME)
annotation class ActivityScope
// Classes annotated with @ActivityScope are scoped to the graph and the same
// instance of that type is provided every time the type is requested.
@ActivityScope
@Subcomponent
interface LoginComponent {
@Subcomponent.Factory
interface Factory {
fun create(): LoginComponent
}
fun inject(activity: DaggerActivity)
// fun activity(): DaggerActivity
}
@Singleton
@Component(modules = [NetworkModule::class, SubcomponentsModule::class])
interface ApplicationGraph {
// The return type of functions inside the component interface is
// what can be provided from the container
fun repository(): UserRepository
// fun inject(activity: Application)
// This function exposes the LoginComponent Factory out of the graph so consumers
// can use it to obtain new instances of LoginComponent
fun loginComponent(): LoginComponent.Factory
}
// Definition of a custom scope called ActivityScope
@Scope
@Retention(value = AnnotationRetention.RUNTIME)
annotation class ActivityScope
// Classes annotated with @ActivityScope are scoped to the graph and the same
// instance of that type is provided every time the type is requested.
@ActivityScope
@Subcomponent
interface LoginComponent {
@Subcomponent.Factory
interface Factory {
fun create(): LoginComponent
}
fun inject(activity: DaggerActivity)
// fun activity(): DaggerActivity
}
class DaggerApp: Application() {
val appComponent = DaggerApplicationGraph.create()
}
class DaggerActivity : AppCompatActivity() {
@Inject
lateinit var loginViewModel: LoginViewModel
lateinit var loginComponent: LoginComponent
override fun onCreate(savedInstanceState: Bundle?) {
val applicationGraph: ApplicationGraph = (applicationContext as DaggerApp).appComponent
applicationGraph.repository().printUserName()
loginComponent = applicationGraph.loginComponent().create()
// Make Dagger instantiate @Inject fields in LoginActivity
loginComponent.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
loginViewModel.toast()
}
}