Dagger with a Hilt
Tags: dagger, android, dependency, injection
Published: 2020-07-24 10:30:55

---
title: Dagger with a Hilt
published: true
description: Super simple dependency injection with Dagger's Hilt
tags: dagger, android, dependency, injection
series: daggerandroidteaching
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/pxobeqfnrg9elwl4eqz2.jpg
---

AndroidEntryPoint is now quite a bit better and in general availability so we can now move to this method!

This lets us specify the bare minimum to have a functional Dagger setup, with few drawbacks and get going really quickly with the code we care about.

Looking to rapidly bootstrap a new app with Dagger and Hilt?
Here are some steps to how it might practically be used. You could go in order to jump to the section you'd like.

* [Setup](#basic-setup)
* [Create an Application class](#create-an-application-class)
* [Let's get a ViewModel, but first..](#lets-get-a-viewmodel-but-first)
* [Creating a Retrofit Provider](#creating-a-retrofit-provider)
* [Creating an API interface for the actual call](#creating-an-api-interface-for-the-actual-call)
* [Creating concrete instances of the API ](#creating-concrete-instances-of-the-api)
* [Creating a Repository](#creating-a-repository)
* [Finally the ViewModel](#finally-the-viewmodel)
* [Wrapping it up in the Activity](#wrapping-it-up-in-the-activity)



## Basic Setup
1. Add `classpath "com.google.dagger:hilt-android-gradle-plugin:2.28-alpha"` to your project level build.gradle (the one at your project root)
2. Add `apply plugin: 'dagger.hilt.android.plugin'` to the top of your app level build.gradle
3. Ensure you have `apply plugin: 'kotlin-kapt'` in your app level build.gradle as well
4. Import the following at the app level build.gradle:

`implementation "com.google.dagger:hilt-android:2.28-alpha"
kapt"com.google.dagger:hilt-android-compiler:2.28-alpha"`


Once you've gotten your setup ready, here's what you do.

## Create an Application class

Then annotate it with `@HiltAndroidApp`
```kotlin
@HiltAndroidApp
class DemoApplication : Application()
```

Don't forget to add the classname of your application to the Manifest!
```xml
    <application
        android:name=".DemoApplication"
        android:allowBackup="true"

```

# Let's get a ViewModel, but first..

Since it's only going to be useful with a repo and some Api passed in:

We're going to be using the standard separation of concerns which means we're going to need three classes
1. The provider for the Retrofit instance
2. The API interface for the network call to be made by retrofit
3. The repository which will take in an instance of the created API and be responsible for exposing it to the ViewModel

We're going to create them in that order only because the app wouldn't compile in an intermediate state otherwise.

### Creating a Retrofit Provider

I'll get to what `@ApplicationComponent` is and why the module is an `object` along with why this particular provider is marked `@Singleton` right after showing you code for this module.

```kotlin
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent
import io.reactivex.schedulers.Schedulers
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import javax.inject.Singleton

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

    @Singleton
    @Provides
    fun getRetrofit(client: OkHttpClient) : Retrofit = Retrofit.Builder().baseUrl("https://something.com")
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .client(client)
        .build()

    @Provides
    fun getClient() : OkHttpClient = OkHttpClient()
}
```

Since we only ever want one instance of Retrofit (to improve connection pooling) this is a Singleton provider.
It might feel odd having a default okhttp client provided but this is often modified with interceptors.

This is installed in the `Application` [component](https://developer.android.com/training/dependency-injection/hilt-android#component-lifetimes) since we want the retrofit instance to not only be unique for the entire app, but also at the highest level in the dependency graph so it's available to all other modules.

This follows the standard practise of Modules being Singletons (via the object notation) for faster runtime performance. 

Note: Since Dagger 2.25, we no longer need to annotate the functions JvmStatic.

### Creating an API interface for the actual call

```kotlin
import io.reactivex.Observable
import retrofit2.http.GET

interface SomethingApi {
    @GET("widgets/")
    fun getWidgets(): Observable<String>
}
```
The pretend API has an endpoint called widgets and we're going to get ourselves some widgets!

### Creating concrete instances of the API
Since it requires retrofit to create concrete instances of the API, we're going to need a module that will manage that.

```kotlin
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityRetainedComponent
import retrofit2.Retrofit

@InstallIn(ActivityRetainedComponent::class)
@Module
object ApiModule {

    @Provides
    fun getSomethingApi(retrofit: Retrofit): SomethingApi =
        retrofit.create(SomethingApi::class.java)
}
```
Note that is in an `ActivityRetainedComponent` since it's intended to be used by a ViewModel that will itself be preserved on activity rotation. The only difference between the `ActivityRetainedComponent` and the `ActivityComponent` is that the provided object in the first scope is 'retained' or kept, through configuration changes. See [here](https://developer.android.com/training/dependency-injection/hilt-android#component-lifetimes)

### Creating a Repository

This repo will abstract away the network and DB api's for the ViewModel

```kotlin

import io.reactivex.Observable
import javax.inject.Inject

class MainRepo @Inject constructor(private val somethingApi: SomethingApi) {
    fun getWidgets() : Observable<String> = somethingApi.getWidgets()
}
```

### Finally the ViewModel
ViewModel Factories no longer need to be created since the Hilt compiler will do that bit of code generation.

You'll need `implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha01"` for the `@ViewModelInject` annotation.

Also `kapt "androidx.hilt:hilt-compiler:1.0.0-alpha01"` for the hilt compiler that will actually generate the ViewModel factories for you.

```kotlin
import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.ViewModel

class MainViewModel @ViewModelInject constructor(
    private val mainRepo: MainRepo
) : ViewModel() {

}
```

# Wrapping it up in the Activity
Now we're ready to use this ViewModel in the Activity and it's done with:

```kotlin
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    private val mainViewModel: MainViewModel by viewModels()

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

To get the `viewModels` delegate, you'll need to add the activity or fragment kotlin extension libraries depending on where you want to use it.
That's `implementation "androidx.activity:activity-ktx:1.2.0-alpha06"` or
`implementation "androidx.fragment:fragment-ktx:1.3.0-alpha06"`

That's it!
You're ready to use dependency injected viewmodels!

If you wanted to use this with fragments and want to share the activity's viewmodel with them, use `activityViewModels` instead of viewmodels in them.

Check back in later to see how to use this with navigation components and with testing.

---

Looking to get your devs up to speed on the latest techniques to boost productivity and your time to market? Reach out to me for consulting at consulting@aniketkadam.com