1. Introduction

* Dagger2, an open source dependency injection library that is commonly used in Android application development, is probably familiar. It helps us to decouple strong relationships between modules and improve project robustness. But its shyness and difficulty really scared off many people. To improve accessibility, Google has launched the Dagger Hilt this time around. So let’s start with the history of Dagger. Dagger was first developed by Square. Yeah, Okhttp and Retrofit were both developed by his family. Then Google forked the project and improved it, and it was the Dagger2 we had been using. And then we have this new Dagger Hilt.

Here is the official Google video on dependency injection, which you can also check out. Bi li bi li: www.bilibili.com/video/BV1wJ…

2. Usage

2.1 import library

Add the following dependencies to your module’s build.gradle.

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 - the compiler: 2.28 alpha'
}
Copy the code

Then add the following classpath to your project’s build.gralde.

buildscript {
    dependencies {
       classpath 'com. Google. Dagger hilt - android - gradle - plugin: 2.28 alpha'}}Copy the code

2.2 Application

In Daager2, you need the Application to inherit from the DaggerApplication, and you need to create the Module of the Application, which is very troublesome. This time, however, you can use the @hiltAndroidApp annotation to complete the dependency injection of the Application. The framework will take care of the rest for us.

@HiltAndroidApp
class App : Application() {}Copy the code

2.3 the Module

Hilt has a LifeCycle that defines many components ahead of time for us to use. As follows:

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

We used to have to manage it ourselves, but this time we can delegate it to Hilt by using @installin annotations, which saves a lot of trouble. Of course, you can also use @provide annotations here.

@Module
@InstallIn(ApplicationComponent::class)
class ApplicationModule {
    @AppHash
    @Provides
    fun provideHash(a): String {
        return hashCode().toString()
    }
}
Copy the code

Here @apphash is a custom annotation, the same as Dagger2.

@Qualifier
@Retention(AnnotationRetention.RUNTIME)
internal annotation class AppHash
Copy the code

2.4 the Activity, fragments

In Dagger2, the use of injection dependencies on activities and fragments is extremely complex and head-scratcher. Especially when adding an Activity or Fragment, you often forget to add dependencies. But Hilt simplifies the process for us by simply annotating @AndroidEntryPoint. @ ContributesAndroidInjector as before.

@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())
    }
}
Copy the code

Here are a few extra points for you.

@JvmField

If the type to be injected contains null, var hash:String? = null, the @jVMField annotation is required.

    @JvmField
    @ActivityHash
    @Inject
    var hash: String? = null
Copy the code

Not if it’s just String.

    @ActivityHash
    @Inject
    lateinit var hash: String
Copy the code
Generate the KTX for the ViewModel

The normal way to generate a ViewModel is to use ViewModelProviders. But this code is so boilerplate that it makes no sense to write. To simplify the boilerplate code, use KTX for activities and fragments.

First, introduce the KTX libraries for Activities and Fragments into the project.

    def activity_version = "1.1.0"
    def fragment_version = "1."
    implementation "androidx.activity:activity-ktx:$activity_version"
    implementation "androidx.fragment:fragment-ktx:$fragment_version"
Copy the code

You also need to set the jvmTarget.

kotlinOptions {
    jvmTarget = "1.8"
}
Copy the code

In the Activity:

// Get ActivityScope ViewModel
private val viewModel by viewModels<MainViewModel>()
Copy the code

In the Fragment:

// Get ActivityScope ViewModel
private val viewModel: MainViewModel by activityViewModels() 
// Get the FragmentScope ViewModel
private val viewModel: MainViewModel by viewModels() 
Copy the code

2.5 the ViewModel

You can save a lot of boilerplate code by annotating Hilt’s @ViewModelInject.

Before we start we need to add a library for 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 - the SNAPSHOT'
    implementation 'androidx. Hilt: hilt - lifecycle - viewmodel: 1.0.0 - the SNAPSHOT'
    kapt 'androidx. Hilt: hilt - compiler: 1.0.0 - the SNAPSHOT'
}
Copy the code

Since we are using SNAPSHOT here, we also need to add the repository path.

allprojects {
    repositories {
        maven {
            url "https://androidx.dev/snapshots/builds/6543454/artifacts/repository/"}}}Copy the code

Here is the code for the ViewModel.

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

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

}
Copy the code

The SampleRepository here is also generated with Hilt, as we’ll see below. And the @assisted annotation is for the infusion of SavedStateHandle. The purpose of SavedStateHandle will not be described here. If you don’t know what it is, check it out. There will be a tutorial on it in the future.

2.6 the Singleton

The usage of Singleton is exactly the same as Dagger2. A Singleton is a Singleton generation. It holds one Singleton for the whole process and no additional Singleton generation is required. Refer to the code below for the use of Singleton.

@Singleton
class SampleRepository @Inject constructor() {}Copy the code

3. The end

Let me just say that the Dagger Hilt is quite handy compared to the shy and confusing usage of Dagger2. Not only does it reduce a lot of boilerplate code, but it also helps us manage the Lifecycle of each component. If you have the chance, try it!

Github:github.com/HyejeanMOON…

Scoped Storage for Android10: juejin.cn/post/684490… Jetpack Room for Android: juejin.cn/post/684490… Android Property Animation tutorial: juejin.cn/post/684490… Android ConstraintLayout: juejin.cn/post/684490… Use of Google MergeAdapter: juejin.cn/post/684490… Paging in Android: juejin.cn/post/684490… Android UI testing Espresso: juejin.cn/post/684490… Android WorkManager: juejin.cn/post/684490…