last update
Jun 2, 2026
license
MITv1.0.0
format
SKILL.md
- 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 - Invoke
// Inside Claude Code, type the skill name as a slash command
> /android-hilt-di help me ship this - 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 }
- 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
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
@Providesmethod 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
itemIdfrom navigation). - Injecting into a
Worker, aBroadcastReceiver, 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:
@HiltAndroidAppon the Application,@AndroidEntryPointon Activities/Fragments.@Module+@InstallIn(SingletonComponent::class)with@Provides, and@Bindsfor interface-to-impl mappings (placed in anabstract class).- ViewModel injection via
@HiltViewModel+@Inject constructor, retrieved withhiltViewModel()(Compose) orby viewModels(). - Assisted injection with
@AssistedInject,@Assisted, and an@AssistedFactoryfor runtime params. - Scoping:
@Singleton,@ActivityRetainedScoped,@ViewModelScoped,@ActivityScoped, plus@Qualifierannotations to disambiguate same-type bindings. - WorkManager via
@HiltWorker+@AssistedInjectand theHiltWorkerFactorywired throughConfiguration.Provider. - Testing with
@HiltAndroidTest,HiltAndroidRule,@UninstallModules,@TestInstallIn, and@BindValue.
Example
curl -fsSL --create-dirs -o ~/.claude/skills/android-hilt-di/SKILL.md https://claudeskil.com/skills/android-hilt-di/SKILL.md
@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
@Bindsover@Providesfor 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;@UninstallModulesis per-class.- A
@ViewModelScopeddependency lives as long as the ViewModel, not the screen — don't reach for@ActivityScopedto share state across config changes. - Call
hiltRule.inject()in@Beforeor your@Injecttest 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/