Hilt components and scopes

Architecture and dependency injection Senior Kotlin 2.0+ API 24+ Reviewed By Best Latest Apps

Pick the fix

Two repositories each get their own OkHttpClient, doubling connection pools. What's the fix?

Options
Hint 1 of 1

Which binding needs to be shared?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A Provide OkHttpClient from a SingletonComponent module annotated @Singleton

Correct. One shared client for the app.

Why not the others?
  • B Mark both repositories @Singleton. The client binding is still unscoped, so each gets a new one.
  • C Use @ViewModelScoped on the client. That still makes one per ViewModel.
  • D Create the client in Application and pass it around manually. Works, but bypasses DI.

30-second answer

Each Hilt component has a lifetime: SingletonComponent (app), ActivityRetainedComponent (survives rotation), ViewModelComponent, ActivityComponent, FragmentComponent and more. A scope annotation like @Singleton or @ViewModelScoped means one instance per component instance. Unscoped bindings create a new instance per injection, which is the cheap default; scope only when sharing is required.

Practise saying it · 35 s. No recording, just a timer

Explain Hilt components and scopes.

Say your answer out loud, then check which of these points you covered:

  • Components have lifetimes
  • Scope means one per component instance
  • Unscoped is the default
  • Scope shared state like clients and databases

Deep dive

Scope state holders that must be shared (caches, HTTP clients, databases) as @Singleton.

@ViewModelScoped shares one instance among everything injected into one ViewModel.

Scoping has a cost: Hilt guards scoped bindings with double-checked locking and keeps them alive.

A binding can only depend on bindings from its own or a parent component.

A singleton client Compile-checked · Kotlin 2.4.21
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Provides @Singleton
    fun client(): OkHttpClient = OkHttpClient.Builder().build()
}

Common mistakes

  • Making everything @Singleton.
  • Scoping a stateless class.
  • Injecting an ActivityComponent binding into a singleton.

Senior take & follow-ups

Explain unscoped as the default and name a real reason to scope.

Follow-up questions

Think of your answer first, then open the hint.

  1. What survives rotation?

    Show hint

    ActivityRetainedComponent and ViewModelComponent bindings.

  2. Why not scope everything?

    Show hint

    It keeps objects alive longer and adds locking for no benefit.

Suggest a fix if something here is wrong or out of date.