DEV Community

Dev Arena
Dev Arena

Posted on • Originally published at

Implementation of Hilt in Retrofit

In this article let's explore how easy to implement the Hilt DI and annotate the Network module to invoke the Countries API.


Components used in the Project.

  • Hilt
  • Coroutine
  • Retrofit
  • Gson
  • ViewBinding
  • Timber
  • ConstraintLayout
  • RecyclerView


Rest Countries - Get information about countries via a RESTful API.

Project Structure

Alt Text

Package Structure

Alt Text


Follow the steps to implement the Hilt DI.

Add Dependencies

Project Level
  • Add the hilt-android-gradle-plugin into the classpath of the project level build.gradle.
buildscript {
    ext.kotlin_version = "1.5.20-M1"
    ext.gradle_version = "4.2.1"
    ext.hilt_version = '2.35'
    ext.core_version = '1.5.0'
    ext.appcompat_version = '1.3.0'
    ext.material_version = '1.3.0'
    ext.constraint_version = '2.0.4'
    ext.coroutines_version = '1.5.0'
    ext.lifecycle_version = '2.3.1'
    ext.activity_version = '1.2.3'
    ext.retrofit_version = '2.6.0'
    ext.httplogging_version = '3.12.0'
    ext.json_version = '2.8.6'
    ext.junit_version = '4.13.2'
    ext.extjunit_version = '1.1.2'
    ext.espressocore_version = '3.3.0'
    ext.timber_version = '4.7.1'

    dependencies {
        classpath "$hilt_version"

Enter fullscreen mode Exit fullscreen mode
App Level
  • Add the plugin into the app level build.gradle.
  • Enable the support for Java 8 features by adding compileOptions in the build.gradle.
  • Add the dagger:hilt-android implementation and dagger:hilt-compiler kapt into the build.gradle.
plugins {
    id ''
    id 'kotlin-android'
    id 'kotlin-kapt'
    id 'kotlin-android-extensions'
    id ''
android {
  compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    kotlinOptions {
        jvmTarget = '1.8'
    buildFeatures {
        viewBinding true
dependencies {
    //  Kotlin
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

    // Core
    implementation "androidx.core:core-ktx:$core_version"
    implementation "androidx.appcompat:appcompat:$appcompat_version"
    implementation "androidx.activity:activity-ktx:$activity_version"

    // UI
    implementation "$material_version"
    implementation "androidx.constraintlayout:constraintlayout:$constraint_version"

    //  Lifecycle Components
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"

    //  Logging
    implementation "com.jakewharton.timber:timber:$timber_version"

    // Hilt DI
    implementation "$hilt_version"
    kapt "$hilt_version"

    //  Coroutines
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"

    implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
    implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
    implementation "com.squareup.okhttp3:logging-interceptor:$httplogging_version"
    implementation "$json_version"

    // Test
    testImplementation "junit:junit:$junit_version"
    androidTestImplementation "androidx.test.ext:junit:$extjunit_version"
    androidTestImplementation "androidx.test.espresso:espresso-core:$espressocore_version"
Enter fullscreen mode Exit fullscreen mode


  • Internet permission(uses-permission) is required for accessing API.
  • Application class should be referred in the android:name attribute.
 <uses-permission android:name="android.permission.INTERNET" />

        <activity android:name=".main.view.MainActivity">
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
Enter fullscreen mode Exit fullscreen mode


Create Application class and annotate with @HiltAndroidApp.

@HiltAndroidApp annotation generates Hilt code for Application class and creates parent container.

class HiltApplication : Application()
Enter fullscreen mode Exit fullscreen mode


Create an Activity and setup the UI & livedata observers. Here, viewbinding is used for inflating the UI. And viewmodel is initialized using the by viewModels() ktx.

@AndroidEntryPoint annotation generates Hilt components for Android classes like Activity, Fragment etc., based on the lifecycle of the respective component.

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private val mainViewModel: MainViewModel by viewModels()

    lateinit var countryAdapter: CountryAdapter
    override fun onCreate(savedInstanceState: Bundle?) {
        binding = ActivityMainBinding.inflate(layoutInflater)
Enter fullscreen mode Exit fullscreen mode


Create the Adapter class for recyclerview with constructor injection.

@Inject annotation used in constructor, field and method injection where dependency is requested. Field injected cannot be private.

class CountryAdapter @Inject constructor() : RecyclerView.Adapter<CountryAdapter.ViewHolder>() {
    var countries: List<Country> = emptyList()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =

    override fun onBindViewHolder(holder: ViewHolder, position: Int) =

    override fun getItemCount(): Int = countries.size

    inner class ViewHolder(private val binding: CountryItemBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(country: Country) {
            binding.apply {
                country.also { (name, capital) ->
                    nameTextview.text = name
                    capitalTextview.text = capital
Enter fullscreen mode Exit fullscreen mode


Create ViewModel class and add method for loading the country list.

@HiltViewModel is annotated to enable viewmodel injection.

class MainViewModel @Inject constructor(private val repository: Repository) : ViewModel() {
    private val countryLiveData = MutableLiveData<List<Country>?>()

    fun getCountry() = countryLiveData

    init {
Enter fullscreen mode Exit fullscreen mode


Create object class with various annotations like @Module, @InstallIn, @Singleton and @Provides which provides dependencies. The Module class supplies the necessary dependent methods for the Network module.

@Module annotated class provides required instances as dependency for various classes.

Hilt Module annotated with @InstallIn specify the scope of the Module. Here, SingletonComponent::class generates singleton container for the class.

@Provides is annotated in the method and provides objects to inject when required.

@Singleton is annotated to create singleton instance of the dependency object and use it throughout the app.

object ApiModule {
    private const val BASE_URL = ""

    fun providesHttpLoggingInterceptor() = HttpLoggingInterceptor()
        .apply {
            level = HttpLoggingInterceptor.Level.BODY

    fun providesOkHttpClient(httpLoggingInterceptor: HttpLoggingInterceptor): OkHttpClient =

    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder()

    fun provideApiService(retrofit: Retrofit): ApiService = retrofit.create(

    fun providesRepository(apiService: ApiService) = Repository(apiService)
Enter fullscreen mode Exit fullscreen mode


Define the Countries list API's in the Service.

interface ApiService {
    suspend fun getCountries(): Response<Countries>
Enter fullscreen mode Exit fullscreen mode


Create an Repository class which returns the list of countries network response.

class Repository(private val apiService: ApiService) {
    suspend fun getCountries() = apiService.getCountries()
Enter fullscreen mode Exit fullscreen mode


Alt Text


Project code is accessible in the GitHub Repo DevArena/HiltRetrofitApp

Happy Coding! 😀

Top comments (1)

devrauluis profile image
Raul Luis

Great tutorial!
How do I add a second API to the project, I've tried adding it to the same module, but it doesn't work, I get a duplicate bindings error