Skillquality 0.45

hilt-di

27 Android skills for AI agents (Claude Code, Codex, Cursor). Fixes Supabase auth, Hilt errors, design inconsistency, kapt→ksp, missing UiState states. Reduced my token bills 5×. FitGenZ AI shipped in 18 days.

Price
free
Protocol
skill
Verified
no

What it does

Hilt Dependency Injection

10 rules that fix what AI agents consistently get wrong with Hilt.

Setup — required before any injection works

// MyApplication.kt — REQUIRED, must be declared in AndroidManifest
@HiltAndroidApp
class MyApplication : Application()

// AndroidManifest.xml
<application android:name=".MyApplication" ...>
// build.gradle.kts — use KSP, never kapt
plugins {
    alias(libs.plugins.ksp)
    alias(libs.plugins.hilt)
}
dependencies {
    implementation(libs.hilt.android)
    ksp(libs.hilt.compiler)                          // ← ksp, not kapt
    implementation(libs.androidx.hilt.navigation.compose)
}

Rule 1: @Binds over @Provides for interface binding

// ✅ @Binds — zero runtime overhead, compiler-verified
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
    @Binds
    @Singleton
    abstract fun bindItemRepository(impl: ItemRepositoryImpl): ItemRepository

    @Binds
    @Singleton
    abstract fun bindUserRepository(impl: UserRepositoryImpl): UserRepository
}

// ❌ @Provides for interface — works but is less efficient
@Module
@InstallIn(SingletonComponent::class)
object RepositoryModule {
    @Provides
    @Singleton
    fun provideItemRepository(impl: ItemRepositoryImpl): ItemRepository = impl
}

Rule 2: @Provides for third-party / constructed objects

// ✅ @Provides when you control construction
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient =
        OkHttpClient.Builder()
            .addInterceptor(HttpLoggingInterceptor().apply { level = Level.BODY })
            .connectTimeout(30, TimeUnit.SECONDS)
            .build()

    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit =
        Retrofit.Builder()
            .baseUrl(BuildConfig.BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(Json.asConverterFactory("application/json".toMediaType()))
            .build()

    @Provides
    @Singleton
    fun provideItemApiService(retrofit: Retrofit): ItemApiService =
        retrofit.create(ItemApiService::class.java)
}

Rule 3: Scope correctly

// @Singleton — one instance for app lifetime
@Binds @Singleton abstract fun bindRepo(impl: RepoImpl): Repo

// @ActivityRetainedScoped — survives rotation, dies with activity backstack
// (default for @HiltViewModel — don't re-declare it)

// @ViewModelScoped — tied to ViewModel lifetime
@Binds @ViewModelScoped abstract fun bindSomeHelper(impl: SomeHelperImpl): SomeHelper

// @ActivityScoped — tied to Activity lifetime (rare)
@Binds @ActivityScoped abstract fun bindNavigator(impl: NavigatorImpl): Navigator

// ❌ Injecting @Singleton into @ViewModelScoped — scope violation, Dagger error

Rule 4: @HiltViewModel — correct pattern

// ✅ ViewModel injection
@HiltViewModel
class HomeViewModel @Inject constructor(
    private val getItems: GetItemsUseCase,
    private val savedStateHandle: SavedStateHandle  // free with Hilt
) : ViewModel() { ... }

// ✅ In Composable — always hiltViewModel(), never viewModel()
@Composable
fun HomeScreen(viewModel: HomeViewModel = hiltViewModel()) { ... }

// ✅ Scoped to NavGraph entry
@Composable
fun CheckoutFlow(navController: NavController) {
    val parentEntry = remember(navController) {
        navController.getBackStackEntry(CheckoutRoute)
    }
    val viewModel: CheckoutViewModel = hiltViewModel(parentEntry)
}

Rule 5: @AndroidEntryPoint on all Android classes that inject

// ✅ Required on: Activity, Fragment, View, Service, BroadcastReceiver
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    @Inject lateinit var analyticsTracker: AnalyticsTracker
}

@AndroidEntryPoint
class NotificationService : Service() {
    @Inject lateinit var notificationHandler: NotificationHandler
}

// ❌ Forgetting @AndroidEntryPoint — results in lateinit not initialized crash
class MainActivity : ComponentActivity() {
    @Inject lateinit var analyticsTracker: AnalyticsTracker  // CRASH: not injected
}

Rule 6: @EntryPoint for non-Hilt classes

// ✅ Access Hilt graph from classes Hilt doesn't manage
@EntryPoint
@InstallIn(SingletonComponent::class)
interface AnalyticsEntryPoint {
    fun analyticsTracker(): AnalyticsTracker
}

// Usage in a ContentProvider or non-Hilt class
val entryPoint = EntryPointAccessors.fromApplication(
    context.applicationContext,
    AnalyticsEntryPoint::class.java
)
val tracker = entryPoint.analyticsTracker()

Rule 7: @AssistedInject for runtime parameters

// ✅ When ViewModel needs a runtime value (e.g., item ID from nav args)
@HiltViewModel(assistedFactory = DetailViewModel.Factory::class)
class DetailViewModel @AssistedInject constructor(
    @Assisted val itemId: String,
    private val getItem: GetItemUseCase
) : ViewModel() {

    @AssistedFactory
    interface Factory {
        fun create(itemId: String): DetailViewModel
    }
}

// In Composable
@Composable
fun DetailScreen(itemId: String) {
    val viewModel: DetailViewModel = hiltViewModel<DetailViewModel, DetailViewModel.Factory>(
        creationCallback = { factory -> factory.create(itemId) }
    )
}

Rule 8: Qualifier for multiple bindings of same type

// ✅ @Qualifier to distinguish between two instances of same type
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class IoDispatcher

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class MainDispatcher

@Module
@InstallIn(SingletonComponent::class)
object DispatchersModule {
    @Provides @IoDispatcher
    fun provideIoDispatcher(): CoroutineDispatcher = Dispatchers.IO

    @Provides @MainDispatcher
    fun provideMainDispatcher(): CoroutineDispatcher = Dispatchers.Main
}

// Usage
@HiltViewModel
class MyViewModel @Inject constructor(
    @IoDispatcher private val ioDispatcher: CoroutineDispatcher
) : ViewModel()

Rule 9: Testing with Hilt

// ✅ @HiltAndroidTest for integration tests
@HiltAndroidTest
class HomeViewModelTest {
    @get:Rule val hiltRule = HiltAndroidRule(this)

    @Inject lateinit var getItems: GetItemsUseCase

    @Before
    fun setUp() { hiltRule.inject() }

    @Test
    fun `loads items successfully`() = runTest {
        val viewModel = HomeViewModel(getItems)
        viewModel.uiState.test {
            assertEquals(HomeUiState.Loading, awaitItem())
            assertTrue(awaitItem() is HomeUiState.Success)
        }
    }
}

// ✅ Replace production bindings in tests
@TestInstallIn(components = [SingletonComponent::class], replaces = [RepositoryModule::class])
@Module
abstract class FakeRepositoryModule {
    @Binds @Singleton
    abstract fun bindItemRepository(impl: FakeItemRepository): ItemRepository
}

Rule 10: Common Dagger compile errors and fixes

ErrorCauseFix
[Dagger/MissingBinding]Missing @Provides / @BindsAdd module with binding
[Dagger/IncompatiblyScopedBindings]Singleton injected into narrower scopeMatch scopes or remove scope annotation
abstract @Provides@Provides in abstract classUse object for @Provides, abstract class for @Binds
@Binds methods must have only one parameterWrong @Binds signatureabstract fun bind(impl: Impl): Interface
lateinit var not initializedMissing @AndroidEntryPointAdd @AndroidEntryPoint to class
Cannot be provided without @Inject or @ProvidesInterface binding missingAdd @Binds module

Deep-dive references

  • references/hilt-testing.md — full test setup with @TestInstallIn and fake modules
  • references/hilt-workmanager.md — @HiltWorker and WorkManager integration

Capabilities

skillsource-piyushverma0skill-hilt-ditopic-agent-skillstopic-ai-agenttopic-androidtopic-antigravitytopic-claude-codetopic-codextopic-cursortopic-gemini-clitopic-hilttopic-jetpack-composetopic-kotlintopic-material3

Install

Installnpx skills add piyushverma0/android-agent-skills
Transportskills-sh
Protocolskill

Quality

0.45/ 1.00

deterministic score 0.45 from registry signals: · indexed on github topic:agent-skills · 8 github stars · SKILL.md body (8,075 chars)

Provenance

Indexed fromgithub
Enriched2026-05-18 19:09:09Z · deterministic:skill-github:v1 · v1
First seen2026-05-18
Last seen2026-05-18

Agent access