Jetpack (7) – Hilt

A brief introduction to Hilt

First impression

Hilt is a dependency injection library designed specifically for Android to reduce the need to manually create instances in a project

Hilt defines a standard way to perform DI in your application by providing a container for each Android class in your project and automatically managing its life cycle for you

Hilt is built on top of the popular DI library Dagger and therefore benefits from the compile-time correctness, runtime performance, scalability, and Android Studio support that Dagger provides.

The basic concept

Dependency injection: Provide required objects in the form of parameters that an application can provide when constructing a class, or pass in dependencies to functions that require individual dependencies

  • Constructor injection
  • Field injection (or setter injection)
// Constructor injection
class Car(private val engine: Engine) {
    fun start(a) {
        engine.start()
    }
}

// Method 2: Field injection
class Car {
    lateinit var engine: Engine

    fun start(a) {
        engine.start()
    }
}

fun main(args: Array) {
    val car = Car()
    car.engine = Engine()
    car.start()
}
Copy the code

Dependency container classes

  • The creation of an implementation class in a container class is similar toSpringEffects in frames

Hilt currently supports the following Android classes

  • Application(By using@HiltAndroidApp)
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

Hilt basic use

Simple injection

  1. HiltAndroidApp annotated Application class

    // BaseApplication.kt
    @HiltAndroidApp
    class BaseApplication : Application(a)Copy the code
  2. Other Android classes with @AndroidEntryPoint annotations provide dependencies

    • If you use@AndroidEntryPointFor aAndroidClass to add annotations must also be for those that depend on that classAndroidClass adds comments. For example, if you have aFragmentTo add a comment, you must also use theFragmentAll of theActivityAdd comments.
    // MainActivity...
    @AndroidEntryPoint
    class MainActivity : AppCompatActivity() {}
    Copy the code
  3. Apply and define Hilt bindings

    • @InjectMember object introduction
    • @InjectConstructor injection
    // Official code
    @AndroidEntryPoint
    class ExampleActivity : AppCompatActivity() {
    
      // '@inject' Member object is imported
      @Inject lateinit var analytics: AnalyticsAdapter
      ...
    }
    
    class AnalyticsAdapter @Inject constructor() {... }Copy the code

Inject the viewmodel

  1. Create a ViewModel

    • I am usinghiltis2.35Version, direct@HiltViewModel, the older version can be used@ViewModelInject
    @HiltViewModel
    class HomeViewModel @Inject constructor() : ViewModel() {}
    Copy the code
  2. Refer to the ViewModel

    // HomeFragment.kt 
    private val viewModel: HomeViewModel by viewModels()
    Copy the code
  3. When there are parameters in the ViewModel

    • @InjectConstructor injection
    // MainViewModel.kt
    @HiltViewModel
    class MainViewModel @Inject constructor(
       private valrepository: WordRepository ) : ViewModel() {... }// WordRepository.kt
    class WordRepository @Inject constructor(
       private valwordDao: WordDao ) {... }Copy the code

Related knowledge points

Hilt module

  • Types cannot be injected through constructors; modules can be used

  • An example of an adaptive interface is used using @Sharing

      // The official code
      interface AnalyticsService {
        fun analyticsMethods(a)
      }
    
      // Constructor-injected, because Hilt needs to know how to
      // provide instances of AnalyticsServiceImpl, too.
      class AnalyticsServiceImpl @Inject constructor(...). : AnalyticsService { ... }@Module
      @InstallIn(ActivityComponent::class)
      abstract class AnalyticsModule {
    
        @Binds
        abstract fun bindAnalyticsService(
          analyticsServiceImpl: AnalyticsServiceImpl
        ): AnalyticsService
      }
    Copy the code
  • Inject the instance using @provides, usually an external library, or you must create the instance using the builder pattern

    // The official code
    @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)
      }
    }
    Copy the code

The same type of binding

  • Hilt provides different implementations of the same type in the form of dependencies, which can be implemented using the @qualifier

    // Official code
    @Qualifier
    annotation class InMemoryLogger
    
    @Qualifier
    annotation class DatabaseLogger
    
    @InstallIn(SingletonComponent::class)
    @Module
    abstract class LoggingDatabaseModule {
    
        @DatabaseLogger
        @Singleton
        @Binds
        abstract fun bindDatabaseLogger(impl: LoggerLocalDataSource): LoggerDataSource
    }
    
    @InstallIn(ActivityComponent::class)
    @Module
    abstract class LoggingInMemoryModule {
    
        @InMemoryLogger
        @ActivityScoped
        @Binds
        abstract fun bindInMemoryLogger(impl: LoggerInMemoryDataSource): LoggerDataSource
    }
    Copy the code

Create entry points using @entryPoint annotations

  • To perform field injection in classes not supported by Hilt, such as ContentProvider, you can create entry points using the @entryPoint annotation

    // Official code
    class LogsContentProvider: ContentProvider() {
    
        @InstallIn(SingletonComponent::class)
        @EntryPoint
        interface LogsContentProviderEntryPoint {
            fun logDao(a): LogDao
        }
        
        ...
        
        private fun getLogDao(appContext: Context): LogDao {
            val hiltEntryPoint = EntryPointAccessors.fromApplication(
                appContext,
                LogsContentProviderEntryPoint::class.java
            )
            return hiltEntryPoint.logDao()
        }
    }
    
    Copy the code

A link to the

Jetpack (1) – Navigation

Jetpack series (Ii) — Lifecycle

Jetpack series (3) – LiveData

Jetpack series (4) – ViewModel

Jetpack series (5) — Room

Jetpack series (6) – Paging3

The resources

codelabs

website