Skip to content

// Wire Hilt dependency injection the right way — modules, scopes, ViewModels, WorkManager, testing.

Android Hilt DI

skill --stat
  • last update

    Jun 2, 2026

  • license

    MITv1.0.0

  • format

    SKILL.md

quickstart.sh
3 steps
  1. Install

    // Downloads SKILL.md into ~/.claude/skills/android-hilt-di/

    $ curl -fsSL --create-dirs -o ~/.claude/skills/android-hilt-di/SKILL.md https://claudeskil.com/skills/android-hilt-di/SKILL.md
  2. Invoke

    // Inside Claude Code, type the skill name as a slash command

    > /android-hilt-di help me ship this
  3. Or copy this from the README

    // extracted kotlin block

    $ @HiltViewModel
    class DetailViewModel @AssistedInject constructor(
      private val repo: ItemRepository,
      @Assisted val itemId: String,
    ) : ViewModel() {
      @AssistedFactory interface Factory { fun create(itemId: String): DetailViewModel }
android-hilt-di/
references
SKILL.md
readonly
name:
Android Hilt DI
slug:
android-hilt-di
version:
v1.0.0
license:
MIT
author:
@chiragthummar16
categories:
tags:
#hilt#dagger#di#kotlin#viewmodel
description:

Wire Hilt dependency injection the right way — modules, scopes, ViewModels, WorkManager, testing.

README.md

android-hilt-di/README.md
6 sections

Android Hilt DI

A senior Android engineer that wires up Hilt dependency injection correctly the first time. It handles the parts that bite people in code review: scope mismatches, missing qualifiers, ViewModel injection that doesn't compile, and test setups that silently use production bindings. For Android developers using Hilt (Dagger) in Kotlin who want production-grade DI without spelunking through Dagger error messages.

When to use it

  • Setting up Hilt in a new module or migrating from manual Dagger.
  • A @Provides method returns the wrong scope and you're getting duplicate instances of a @Singleton.
  • You need to inject a ViewModel that takes runtime arguments (e.g. an itemId from navigation).
  • Injecting into a Worker, a BroadcastReceiver, or a non-Hilt-entry-point class.
  • Your instrumented tests pass with the real network layer because the fake binding never replaced it.

How it works

The skill scaffolds and reviews the real Hilt surface area:

  • @HiltAndroidApp on the Application, @AndroidEntryPoint on Activities/Fragments.
  • @Module + @InstallIn(SingletonComponent::class) with @Provides, and @Binds for interface-to-impl mappings (placed in an abstract class).
  • ViewModel injection via @HiltViewModel + @Inject constructor, retrieved with hiltViewModel() (Compose) or by viewModels().
  • Assisted injection with @AssistedInject, @Assisted, and an @AssistedFactory for runtime params.
  • Scoping: @Singleton, @ActivityRetainedScoped, @ViewModelScoped, @ActivityScoped, plus @Qualifier annotations to disambiguate same-type bindings.
  • WorkManager via @HiltWorker + @AssistedInject and the HiltWorkerFactory wired through Configuration.Provider.
  • Testing with @HiltAndroidTest, HiltAndroidRule, @UninstallModules, @TestInstallIn, and @BindValue.

Example

bash
curl -fsSL --create-dirs -o ~/.claude/skills/android-hilt-di/SKILL.md https://claudeskil.com/skills/android-hilt-di/SKILL.md
kotlin
@HiltViewModel
class DetailViewModel @AssistedInject constructor(
  private val repo: ItemRepository,
  @Assisted val itemId: String,
) : ViewModel() {
  @AssistedFactory interface Factory { fun create(itemId: String): DetailViewModel }
}

// In a test module:
@TestInstallIn(components = [SingletonComponent::class], replaces = [NetworkModule::class])
@Module object FakeNetworkModule {
  @Provides fun api(): Api = FakeApi()
}

Tips & gotchas

  • Use @Binds over @Provides for interface bindings — it generates less code and can't accidentally call a constructor with the wrong scope.
  • @TestInstallIn (not just @UninstallModules) is the durable way to swap bindings across a whole test source set; @UninstallModules is per-class.
  • A @ViewModelScoped dependency lives as long as the ViewModel, not the screen — don't reach for @ActivityScoped to share state across config changes.
  • Call hiltRule.inject() in @Before or your @Inject test fields stay null.

FAQ

@Singleton vs @ViewModelScoped? @Singleton lives for the app process; @ViewModelScoped is recreated per ViewModel. Use the latter for per-screen caches you want garbage-collected when the user leaves.

Why "cannot be provided without an @Inject constructor"? The type has no binding in the installed component — add @Provides/@Binds, or check you used the right @InstallIn component.

Does Hilt replace constructor injection? No — it builds the graph around plain @Inject constructor. You only write modules for types you don't own or interfaces.

$ cat reviews/

Reviews

// No reviews yet. Be the first.
Loading review form…

$ ls related/

explore all →