0
点赞
收藏
分享

微信扫一扫

Jetpack 新成员 Hilt 实践(一)启程过坑记,kotlin单例模式

Star英 2022-01-20 阅读 117

Hilt 提供了以下组件来绑定依赖与 对应的 Android 类的活动范围。

Hilt 提供的组件对应的 Android 类的活动范围
ApplicationComponentApplication
ActivityRetainedComponentViewModel
ActivityComponentActivity
FragmentComponentFragment
ViewComponentView
ViewWithFragmentComponentView annotated with @WithFragmentBindings
ServiceComponentService

注意:Hilt 没有为 broadcast receivers 提供组件,因为 Hilt 直接从 ApplicationComponent 注入 broadcast receivers。

Hilt 会根据相应的 Android 类生命周期自动创建和销毁生成的组件类的实例,它们的对应关系如下表格所示。

Hilt 提供的组件创建对应的生命周期销毁对应的生命周期
ApplicationComponentApplication#onCreate()Application#onDestroy()
Acti
vityRetainedComponentActivity#onCreate()Activity#onDestroy()
ActivityComponentActivity#onCreate()Activity#onDestroy()
FragmentComponentFragment#onAttach()Fragment#onDestroy()
ViewComponentView#super()View destroyed
ViewWithFragmentComponentView#super()View destroyed
ServiceComponentService#onCreate()Service#onDestroy()

@Provides

它常用于被 @Module 注解标记类的内部的方法,并提供依赖项对象。

@Module
@InstallIn(ApplicationComponent::class)
// 这里使用了 ApplicationComponent,因此 NetworkModule 绑定到 Application 的生命周期。
object NetworkModule {

/**

  • @Provides 常用于被 @Module 注解标记类的内部的方法,并提供依赖项对象。
  • @Singleton 提供单例
    */
    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
    return OkHttpClient.Builder()
    .build()
    }
    }

@EntryPoint

Hilt 支持最常见的 Android 类 Application、Activity、Fragment、View、Service、BroadcastReceiver 等等,但是您可能需要在Hilt 不支持的类中执行依赖注入,在这种情况下可以使用 @EntryPoint 注解进行创建,Hilt 会提供相应的依赖。

基本概念介绍完了之后,我们正式在项目中使用 Hilt。

如何使用 Hilt

首先需要添加 Hilt 依赖,Hilt 依赖添加方式相比于 Koin 太麻烦了,首先在 project 的 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 {

}

dependencies {
implementation “com.google.dagger:hilt-android:2.28-alpha”
kapt “com.google.dagger:hilt-android-compiler:2.28-alpha”
}

坑:需要注意的是如果同时使用 hilt 和 data binding,Android Studio 的版本必须 >= 4.0

Hilt 使用 Java 8 的功能,所以要在项目中启用 Java 8,需要在 App 模块的 build.gradle 文件中,添加以下代码

android {

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

// For Kotlin projects
kotlinOptions {
jvmTarget = “1.8”
}
}

注意: 这里有一个坑,对于 Kotlin 项目,需要添加 kotlinOptions,这是 Google 文档 Dependency injection with Hilt 中没有提到的,否则使用 ViewModel 会编译不过,下文会有详细的讲解。

Application 是 App 的入口,所以所有使用 Hilt 的 App 必须包含一个使用 @HiltAndroidApp 注解的 Application

@HiltAndroidApp
class HiltApplication : Application() {
/**

    1. 所有使用 Hilt 的 App 必须包含一个使用 @HiltAndroidApp 注解的 Application
    1. @HiltAndroidApp 将会触发 Hilt 代码的生成,包括用作应用程序依赖项容器的基类
    1. 生成的 Hilt 组件依附于 Application 的生命周期,它也是 App 的父组件,提供其他组件访问的依赖
    1. 在 Application 中设置好 @HiltAndroidApp 之后,就可以使用 Hilt 提供的组件了,
  • Hilt 提供的 @AndroidEntryPoint 注解用于提供 Android 类的依赖(Activity、Fragment、View、Service、BroadcastReceiver)等等
  • Application 使用 @HiltAndroidApp 注解
    */
    }
  1. @HiltAndroidApp 将会触发 Hilt 代码的生成,包括用作应用程序依赖容器的基类
  2. 生成的 Hilt 组件依附于 Application 的生命周期,它也是 App 的父组件,提供其他组件访问的依赖

准备工作都做完了,接下来我们来看几个例子,如何使用 Hilt 进行依赖注入。

如何使用 Hilt 进行依赖注入

我们先来看一个简单的例子,注入 HiltSimple 并在 Application 中调用它的 doSomething 方法。

class HiltSimple @Inject constructor() {
fun doSomething() {
Log.e(TAG, “----doSomething----”)
}
}

@HiltAndroidApp
class HiltApplication : Application() {
@Inject
lateinit var mHiltSimple: HiltSimple

override fun onCreate() {
super.onCreate()
mHiltSimple.doSomething()
}
}

Hilt 需要知道如何从相应的组件中提供必要依赖的实例。使用 @Inject 注解来告诉 Hilt 如何提供该类的实例,@Inject 常用于构造函数、非私有字段、方法中。

Hilt 如何和 Android 组件一起使用

如果是 Hilt 支持的 Android 组件,直接使用 @AndroidEntryPoint 注解即可。

/**
*

  • 为项目中的每个 Android 类生成一个 Hilt 组件,这些组件可以从它们各自的父类接收依赖项,
  • 如果是抽象类则不能使用 @AndroidEntryPoint 注解
  • 如果使用 @AndroidEntryPoint 注解 Android 类,还必须注解依赖于它的 Android 类,
  • 例如 如果 注解 fragment 然后还必须注解 fragment 依赖的 Activity, 否则会抛出以下异常
  • java.lang.IllegalStateException: Hilt Fragments must be attached to an @AndroidEntryPoint Activity. Found: class com.hi.dhl.hilt.MainActivity
    */
    @AndroidEntryPoint
    class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 用到了 Fragment 1.2.0 中重要的更新
// 可以查看之前写的这篇文章 @see https://juejin.im/post/6844904167685750798
supportFragmentManager.beginTransaction()
.add(R.id.container, HiltFragment::class.java, null)
.commit()
}
}

/**

  • 如果 注解 fragment 然后还必须注解 fragment 依赖的 Activity, 否则会抛出以下异常
  • java.lang.IllegalStateException: Hilt Fragments must be attached to an @AndroidEntryPoint Activity. Found: class com.hi.dhl.hilt.MainActivity
    */
    @AndroidEntryPoint
    class HiltFragment : Fragment() {

// 使用 @Inject 注解从组件中获取依赖
@Inject
lateinit var mHiltSimple: HiltSimple

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_hilt, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mHiltSimple.doSomething()
}
}

  • 如果是抽象类则不需要使用 @AndroidEntryPoint 注解。
  • @AndroidEntryPoint 注解 仅仅支持 ComponentActivity 的子类例如 FragmentActivity、AppCompatActivity 等等。
  • 如果使用 @AndroidEntryPoint 注解 Android 类,必须在它依赖的 Android 类添加同样的注解,例如在 Fragment 中添加 @AndroidEntryPoint 注解,必须在 Fragment 依赖的 Activity 上也添加 @AndroidEntryPoint 注解。

Hilt 如何和第三方组件一起使用

如果要在项目中注入第三方依赖,我们需要使用 @Module 注解,使用 @Module注解的普通类,在其中创建第三方依赖的对象。

@Module
@InstallIn(ApplicationComponent::class)
// 这里使用了 ApplicationComponent,因此 NetworkModule 绑定到 Application 的生命周期。
object NetworkModule {

/**

  • @Provides 常用于被 @Module 注解标记类的内部的方法,并提供依赖项对象。
  • @Singleton 提供单例
    */
    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
    return OkHttpClient.Builder()
    .build()
    }

@Provides
@Singleton
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.client(okHttpClient)
.baseUrl(“https://api.github.com/”)
.addConverterFactory(GsonConverterFactory.create())
.build()
}

@Provides
@Singleton
fun provideGitHubService(retrofit: Retrofit): GitHubService {
return retrofit.create(GitHubService::class.java)
}
}

  • @Module 常用于创建依赖类的对象(例如第三方库 OkHttp、Retrofit等等)。
  • 使用 @Module 注入的类,需要使用 @InstallIn 注解指定 module 的范围,会绑定到 Android 类对应的生命周期上。
  • @Provides 常用于被 @Module 注解标记类的内部的方法,并提供依赖项对象。

Hilt 如何和 ViewModel 一起使用

在 App 模块中的 build.gradle 文件中添加以下代码。

implementation ‘androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01’
kapt ‘androidx.hilt:hilt-compiler:1.0.0-alpha01’

注意: 这个是在 Google 文档上没有提到的,如果使用的是 kotlin 的话需要额外在 App 模块中的 build.gradle 文件中添加以下代码,否则调用 by viewModels() 会编译不过。

// For Kotlin projects
kotlinOptions {
jvmTarget = “1.8”
}

在 ViewModel 对象的构造函数中使用 @ViewModelInject 注解提供一个 ViewModel。

class HiltViewModel @ViewModelInject constructor(
) : ViewModel() {

/**

  • 在 LifeCycle 2.2.0 之后,可以用更精简的方法来完成,使用 LiveData 协程构造方法 (coroutine builder)。
  • liveData 协程构造方法提供了一个协程代码块,产生的是一个不可变的 LiveData,emit() 方法则用来更新 LiveData 的数据。
  • 具体可以查看之前写的这篇文章 [https://juejin.im/post/6844904193468137486#heading-10] 有详细介绍
    */
    val mHitLiveData = liveData {
    emit(" i am a ViewModelInject")
    }
    }

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

private val mHitViewModule: HiltViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

mHitViewModule.mHitLiveData.observe(this, Observer {
tvResult.setText(it)
})
}
}

在 HiltViewModel 里面使用了 LifeCycle 2.2.0 之后新增的方法,LiveData 协程构造方法提供了一个协程代码块,产生的是一个不可变的 LiveData,emit() 方法则用来更新 LiveData 的数据,具体可以查看之前写的这篇文章 Jetpack 成员 Paging3 实践以及源码分析(一) 里面有详细介绍。

Hilt 如何和 Room 一起使用

这里需要用到 @Module 注解,使用 @Module 注解的普通类,在其中提供 Room 的实例。

@Module
@InstallIn(ApplicationComponent::class)
// 这里使用了 ApplicationComponent,因此 NetworkModule 绑定到 Application 的生命周期。
object RoomModule {

/**

  • @Provides 常用于被 @Module 注解标记类的内部的方法,并提供依赖项对象。
  • @Singleton 提供单例
举报

相关推荐

0 条评论