Hilt是Google根据Dagger2开发的专用于Android的依靠注入结构,比较Dagger,它的优势如下:

  • 简化了Android运用中Dagger相根底架构
  • 创立了一组标准的组件和效果域,以简化设置、提高可读性以及在运用之间共享代码。
  • 供给了一种简略的办法来为各种构建类型(如测验、调试或发布)装备不同的绑定。

引入依靠

  1. 在项目根级build.gradle中增加hilt-android-gradle-plugin插件。

    buildscript {
        dependencies {
            classpath 'com.google.dagger:hilt-android-gradle-plugin:x.y.z'
        }
    }
    
  2. 在模块级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中的依靠项。

依赖注入(十)—— Jetpack Hilt

组件的生命周期

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()

比较ActivityComponentActivityRetainedComponent在运用装备更改(如反正屏)引起Activity重建后依然存在。

❓ Q:ActivityRetainedComponentActivityComponent创立和毁掉机遇共同,为何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