神同樣的存在,Dagger Hilt !!

1.簡介

你們應該都多多少少了解在Android應用開發中會廣泛用到的依賴注入開源庫ー Dagger2。它能很好幫咱們解耦各個模塊之間的強關聯性,提升項目的健壯性。可是它的羞澀難懂,難用着實嚇退了很多人。爲了提升易用性,此次谷歌推出了 Dagger Hilt
那麼首先咱們從Dagger的歷史開始講起吧。
Dagger首先是由Square公司開發。對,Okhttp和Retrofit都是他們家開發的。後來谷歌Fork了這個項目並進行了改進,這就是咱們以前一直在用的 Dagger2。而後就是此次新推出的 Dagger Hilt

這裏有關於依賴注入的Google官方的視頻,你們也能夠看一下。
嗶哩嗶哩:www.bilibili.com/video/BV1wJ…android

2. 使用方法

2.1 引入庫

在模塊的build.gradle中加入下列依賴。git

apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'kotlin-kapt'

dependencies {
    implementation 'com.google.dagger:hilt-android:2.28-alpha'
    kapt 'com.google.dagger:hilt-android-compiler:2.28-alpha'
}
複製代碼

而後在項目的build.gralde中加入下面classpathgithub

buildscript {
    dependencies {
       classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
    }
}
複製代碼

2.2 Application

若是是在Daager2的話,須要Application繼承DaggerApplication,而且還須要建立Application的Module,甚是麻煩。
可是此次只要使用@HiltAndroidApp的註解就能夠完成對Application的依賴注入。剩下的部分框架會爲咱們解決。app

@HiltAndroidApp
class App : Application() {
}
複製代碼

2.3 Module

Hilt爲了方便咱們使用提早定義了好多組件的LifeCycle。以下:框架

  • Application
  • Activity
  • ActivityRetained
  • Fragment
  • Service
  • View
  • ViewWithFragment

之前咱們須要本身管理,可是此次只要使用@InstallIn的註解,就能夠委託Hilt幫咱們管理,能夠省去不少麻煩。固然在這裏也可使用@Provide註解。jvm

@Module
@InstallIn(ApplicationComponent::class)
class ApplicationModule {
    @AppHash
    @Provides
    fun provideHash(): String {
        return hashCode().toString()
    }
}
複製代碼

這裏的@AppHash是自定義註解,跟Dagger2的用法是同樣的。maven

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
internal annotation class AppHash
複製代碼

2.4 Activity, Fragment

Dagger2中,對Activity和Fragment的注入依賴的使用方法異常複雜,讓人抓耳撓腮。尤爲是新增一個Activity或Fragment時常常忘了添加依賴。
可是在Hilt中爲咱們簡化了這一個過程,只須要@AndroidEntryPoint的註解。至關於以前的@ContributesAndroidInjectoride

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    @JvmField
    @ActivityHash
    @Inject
    var hash: String? = null
    private val viewModel by viewModels<MainViewModel>()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        textView.text = hash
        Log.d("MainActivity", viewModel.getRepositoryString())
    }
}
複製代碼

在這裏爲你們講幾個額外的知識點。post

@JvmField

若是要注入的類型包含空,即像上述代碼var hash:String? = null時,須要添加@JvmField註解。測試

@JvmField
    @ActivityHash
    @Inject
    var hash: String? = null
複製代碼

若是隻是String類型則不須要。

@ActivityHash
    @Inject
    lateinit var hash: String
複製代碼
生成ViewModel的KTX

若是是正常的生成ViewModel的是方法是使用ViewModelProviders。可是這些代碼太過於樣板代碼,寫起來毫無心義。這個時候爲了簡化這些樣板代碼就可使用ActivityFragmentKTX

首先把ActivityFragmentKTX的庫引入到項目中。

def activity_version = "1.1.0"
    def fragment_version = "1.2.4"
    implementation "androidx.activity:activity-ktx:$activity_version"
    implementation "androidx.fragment:fragment-ktx:$fragment_version"
複製代碼

還須要設置jvmTarget

kotlinOptions {
    jvmTarget = "1.8"
}
複製代碼

在Activity中:

// 獲取ActivityScope的ViewModel
private val viewModel by viewModels<MainViewModel>()
複製代碼

在Fragment中:

// 獲取ActivityScope的ViewModel
private val viewModel: MainViewModel by activityViewModels() 
// 獲取FragmentScope的ViewModel
private val viewModel: MainViewModel by viewModels() 
複製代碼

2.5 ViewModel

只要使用Hilt@ViewModelInject的註解,框架不只爲咱們解決生成問題,還幫咱們解決Lifecycle問題。可算是進一步減小了樣板代碼的存在。

首先開始以前咱們須要添加一下關於ViewModel-lifecycle的庫。

dependencies {
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0'

    implementation 'androidx.hilt:hilt-common:1.0.0-SNAPSHOT'
    implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-SNAPSHOT'
    kapt 'androidx.hilt:hilt-compiler:1.0.0-SNAPSHOT'
}
複製代碼

由於這裏咱們使用了SNAPSHOT,因此咱們還須要添加repository的路徑。

allprojects {
    repositories {
        maven {
            url "https://androidx.dev/snapshots/builds/6543454/artifacts/repository/"
        }
    }
}
複製代碼

下面就是關於ViewModel的代碼。

class MainViewModel @ViewModelInject constructor(
    private val repository: SampleRepository,
    @Assisted private val savedState: SavedStateHandle
) : ViewModel() {

    fun getRepositoryString(): String = repository.toString()

}
複製代碼

這裏的SampleRepository是也是用Hilt生成的,下面會有講到。
還有@Assisted的註解是爲了注入SavedStateHandle。這裏就對SavedStateHandle的用途就不敘述了,不懂的小夥伴搜一搜資料瞭解一下。之後有機會的話會出關於它的教程。

2.6 Singleton

關於Singleton的用法跟Dagger2是徹底同樣的。怕有人不知道,簡單解釋一下Singleton就是單例生成,全程持有一個單例,再也不額外生成。
關於Singleton的用法參考下面的代碼。

@Singleton
class SampleRepository @Inject constructor() {

}
複製代碼

3. 結尾

讓我感嘆一下,對比以前的Dagger2用法的羞澀難懂,Dagger Hilt真是好用啊。不只減小了不少樣板代碼,並且還幫咱們管理各個組件的Lifecycle。若是你們有機會必定要嘗試嘗試!

Github:github.com/HyejeanMOON…

其餘教程:
Android10的分區存儲機制(Scoped Storage)適配教程:juejin.im/post/5ec005…
Android Jetpack Room的詳細教程: juejin.im/post/5ebac9…
Android的屬性動畫(Property Animation)詳細教程: juejin.im/post/5eb7a5…
Android ConstraintLayout的易懂教程: juejin.im/post/5ea50a…
在RecyclerView中能夠應對多個ViewType的庫--Groupie: juejin.im/post/5e9059…
Google的MergeAdapter的使用: juejin.im/post/5e903f…
Paging在Android中的應用: juejin.im/post/5e75db…
Android UI測試之Espresso: juejin.im/post/5e6caa…
Android WorkManager的使用: juejin.im/post/5e635e…

相關文章
相關標籤/搜索