JoJo的个人博客

记录精彩的程序人生

目录
Jetpack系列之Hilt
/    

Jetpack系列之Hilt

简介

依赖注入有什么用?

  • 自动加载
  • 自动加载的关键:数据共享
  • 需要被共享的数据应该用依赖注入

hilt 有什么用

  • 更方便的进行依赖注入
  • 能方便的实现全局共享或者局部共享

Koin

  • 使用方便

  • 但是会在运行时解析,增加性能消耗

添加依赖项

  • 项目的根级 build.gradle 文件中配置
  buildscript {
      ...
      dependencies {
          ...
          classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
      }
  }
  • app/build.gradle 文件中添加以下依赖项
  ...
  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.28-alpha"
      kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
  }

Hilt 应用类

@HiltAndroidApp
class ExampleApplication : Application() { ... }

将依赖项注入 Android 类

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() { ... }

Hilt 目前支持以下 Android 类:

  • Application(通过使用 @HiltAndroidApp
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

如果您使用 @AndroidEntryPoint 为某个 Android 类添加注释,则还必须为依赖于该类的 Android 类添加注释。例如,如果您为某个 Fragment 添加注释,则还必须为使用该 Fragment 的所有 Activity 添加注释

@Inject

注入

  • 如需从组件获取依赖项,使用 @Inject 注释执行字段注入,但是不能注入私有字段
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject lateinit var user: User
    ....
}
  • 构造函数注入,在某个类的构造函数中使用 @Inject 注释,以告知 Hilt 如何提供该类的实例
  class AnalyticsAdapter @Inject constructor(private val service: AnalyticsService) {
     ...
  }

提供实例

open class User constructor(var id: Intvar name: String, var mood: String) {

    @Inject constructor() : this(1"新用户""毫无波澜")
}

Hilt 模块

@Binds

使用 @Binds 注入接口实例

AnalyticsService 为例。如果 AnalyticsService 是一个接口,则您无法通过构造函数注入它,而应向 Hilt 提供绑定信息,方法是在 Hilt 模块内创建一个带有 @Binds 注释的抽象函数

@Binds 注释会告知 Hilt 在需要提供接口的实例时要使用哪种实现

@Module
@InstallIn(ApplicationComponent::class)
abstract class HiltModule {

    @Binds
    abstract fun bindAnalyticsService(
      analyticsServiceImpl: AnalyticsServiceImpl
    )
: AnalyticsService
}

interface AnalyticsService {
    fun analyticsMethods()
}

// Constructor-injected, because Hilt needs to know how to
// provide instances of AnalyticsServiceImpl, too.
class AnalyticsServiceImpl @Inject constructor() : AnalyticsService {

    override fun analyticsMethods() {
        Log.d("AnalyticsServiceImpl""analyticsMethods...")
    }
}

@Provides

使用 @Provides 注入实例,这种方式会更通用一些

如果某个类不归您所有(因为它来自外部库,如 RetrofitOkHttpClientRoom 数据库等类),或者必须使用构建器模式创建实例,也无法通过构造函数注入

@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)
  }
}
为同一类型提供多个绑定

如果需要让 Hilt 以依赖项的形式提供同一类型的不同实现,必须向 Hilt 提供多个绑定。可以使用限定符为同一类型定义多个绑定。

@Module
@InstallIn(ApplicationComponent::class)
object HiltModule2 {

    @Provides
    fun provideUser(): User {
        val user = User(999"aaa""难过")
        return user
    }

    @AUser
    @Provides
    fun provideAGoodUser(user: User): GoodUser {
        return GoodUser(user, "AUser")
    }

    @BUser
    @Provides
    fun provideBGoodUser(user: User): GoodUser {
        return GoodUser(user, "BUser")
    }
}


@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AUser

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class BUser

//使用时
@AUser
@Inject
lateinit var aUser: GoodUser


为 Android 类生成的组件

对于您可以从中执行字段注入的每个 Android 类,都有一个关联的 Hilt 组件,您可以在 @InstallIn 注释中引用该组件。每个 Hilt 组件负责将其绑定注入相应的 Android 类。

Hilt 组件 注入器面向的对象
ApplicationComponent Application
ActivityRetainedComponent ViewModel
ActivityComponent Activity
FragmentComponent Fragment
ViewComponent View
ViewWithFragmentComponent 带有 @WithFragmentBindings 注释的 View
ServiceComponent Service

组件生命周期

Hilt 会按照相应 Android 类的生命周期自动创建和销毁生成的组件类的实例。

生成的组件 创建时机 销毁时机
ApplicationComponent Application#onCreate() Application#onDestroy()
ActivityRetainedComponent Activity#onCreate() Activity#onDestroy()
ActivityComponent Activity#onCreate() Activity#onDestroy()
FragmentComponent Fragment#onAttach() Fragment#onDestroy()
ViewComponent View#super() 视图销毁时
ViewWithFragmentComponent View#super() 视图销毁时
ServiceComponent Service#onCreate() Service#onDestroy()

Scope 作用域

限制作用域,可以标识在被被注入类,或者与@Provides配合使用

  • @Singleton 全局共享

  • ActivityScoped

    使用 @ActivityScoped 将作用域限定为 ActivityComponent,Hilt 会在相应 Activity 的整个生命周期内提供 同一实例

类似的还有FragmentScopedViewScoped

组件默认绑定

每个 Hilt 组件都附带一组默认绑定

Android 组件 默认绑定
ApplicationComponent Application
ActivityRetainedComponent Application
ActivityComponent ApplicationActivity
FragmentComponent ApplicationActivityFragment
ViewComponent ApplicationActivityView
ViewWithFragmentComponent ApplicationActivityFragmentView
ServiceComponent ApplicationService

还可以使用 @ApplicationContext 获得应用上下文绑定。例如:

class AnalyticsServiceImpl @Inject constructor(
  @ApplicationContext context: Context
) : AnalyticsService { ... }

// The Application binding is available without qualifiers.
class AnalyticsServiceImpl @Inject constructor(
  application: Application
) : AnalyticsService { ... }

此外,还可以使用 @ActivityContext 获得 Activity 上下文绑定。例如:

class AnalyticsAdapter @Inject constructor(
  @ActivityContext context: Context
) { ... }

// The Activity binding is available without qualifiers.
class AnalyticsAdapter @Inject constructor(
  activity: FragmentActivity
) { ... }

github

github 参考示例 HiltSample

参考资料

Android 开发者文档

凯哥视频


标题:Jetpack系列之Hilt
作者:SunnySky
地址:https://www.tianyang.pub/articles/2020/11/17/1605546856682.html

评论