Hilt Basics Quiz
ARCHITECTURE › Dependency Injection
Which annotation must be present on the Application class for Hilt to work?
- @AndroidEntryPoint
- @HiltAndroidApp
- @HiltApplication
- @InstallIn(SingletonComponent::class)
Answer: @HiltAndroidApp
@HiltAndroidApp on the Application triggers Hilt's code generation and creates the app-level container; it is required for any Hilt app.
You need to provide an interface whose implementation you own and can annotate with @Inject. What is the most appropriate Hilt construct?
- A @Provides function that delegates to a builder
- An @EntryPoint interface resolved at runtime
- A @Binds abstract function inside a @Module
- @AndroidEntryPoint applied to the consumer class
Answer: A @Binds abstract function inside a @Module
@Binds is the idiomatic, lower-overhead way to map an interface to an @Inject-annotated implementation you own; @Provides is reserved for cases where you must construct the instance yourself.
Which scope binds an instance to the lifetime of a single Hilt ViewModel?
- @ViewModelScoped
- @ActivityScoped
- @Singleton
- @ActivityRetainedScoped
Answer: @ViewModelScoped
@ViewModelScoped is provided by ViewModelComponent and keeps one instance per ViewModel; the others are tied to activity, application, or config-change-surviving lifetimes respectively.
Two @Provides functions return OkHttpClient. How do you make Hilt inject the right one at each injection point?
- Mark one binding @Singleton and leave the other one unscoped
- Put each @Provides function in a different @Module
- Use @Named only on the consumer injection side
- Define @Qualifier annotations and apply them to both sides
Answer: Define @Qualifier annotations and apply them to both sides
Qualifiers disambiguate multiple bindings of the same type; the qualifier must be applied to each binding and to the matching injection point. Scoping or splitting modules does not resolve the ambiguity.
In Jetpack Compose, what is the correct way to obtain a Hilt-injected ViewModel inside a composable?
- hiltViewModel()
- viewModel()
- remember { ExampleViewModel() }
- by viewModels()
Answer: hiltViewModel()
hiltViewModel() retrieves a @HiltViewModel scoped to the current nav destination/owner. by viewModels() is a property delegate for Activities/Fragments, not composables, and plain viewModel() does not use Hilt's injection.
What does Hilt actually generate to perform injection at runtime?
- Reflection-based service locators built at app startup time
- One global runtime map of types to their singleton instances
- Dagger components per Android class, checked at compile time
- Kotlin synthetic accessors that skip any graph validation
Answer: Dagger components per Android class, checked at compile time
Hilt is a layer over Dagger; it generates and wires Dagger components per Android class and validates the dependency graph at compile time, failing the build on missing dependencies or cycles.
Which statement about @Inject field injection via @AndroidEntryPoint is correct?
- Injected fields may be private and still be assigned directly
- It can be applied to any plain Kotlin class without support
- Injected fields cannot be private or compilation fails
- It removes the need for an @HiltAndroidApp Application class
Answer: Injected fields cannot be private or compilation fails
Hilt injects fields by assigning them directly, so @Inject lateinit var fields must not be private. @AndroidEntryPoint only works on supported Android classes and still requires @HiltAndroidApp on the Application.
What does the @InstallIn annotation on a Hilt @Module declare?
- That the module should only be processed in debug builds and tests.
- Which Hilt component hosts the module's bindings, and thus their scope.
- That the module declares Gradle dependencies needed for Hilt to compile.
- That the module is the app's entry point and must be initialized first.
Answer: Which Hilt component hosts the module's bindings, and thus their scope.
@InstallIn(SingletonComponent::class) and similar tell Hilt which generated component hosts the bindings, which determines the lifetime and where those bindings are available; it is mandatory on every Hilt module.
You need a Hilt-provided dependency inside a class Hilt cannot field-inject, such as a ContentProvider. What is the supported approach?
- Define an @EntryPoint in the right component, then use EntryPointAccessors
- Add @AndroidEntryPoint to the ContentProvider and inject fields directly
- Build the generated Dagger component yourself, then call its constructor manually
- Expose the dependency as a global top-level object and read it from anywhere
Answer: Define an @EntryPoint in the right component, then use EntryPointAccessors
@EntryPoint plus EntryPointAccessors is Hilt's escape hatch for reaching the graph from classes it does not support; ContentProvider is explicitly not supported by @AndroidEntryPoint.
In an instrumented test annotated with @HiltAndroidTest, what is the standard way to replace a production module's bindings with fakes?
- Mutate the SingletonComponent via reflection at runtime to swap bindings
- Subclass and override the Application class by hand for each test case
- There is no supported mechanism, so Hilt has to be avoided in tests
- Use @TestInstallIn or @UninstallModules, plus @BindValue for fakes
Answer: Use @TestInstallIn or @UninstallModules, plus @BindValue for fakes
Hilt's testing APIs (@UninstallModules, @TestInstallIn, and @BindValue) are the designed way to substitute bindings; the test runs against the generated HiltTestApplication.
How do you enable Hilt injection into a WorkManager ListenableWorker?
- Annotate the worker with @AndroidEntryPoint for injection
- Nothing special is needed; WorkManager uses @Inject itself
- Use @HiltWorker with @AssistedInject and HiltWorkerFactory
- Provide the worker from a @Provides method in SingletonComponent
Answer: Use @HiltWorker with @AssistedInject and HiltWorkerFactory
@HiltWorker combined with @AssistedInject lets Hilt supply other dependencies while WorkManager supplies the Context and WorkerParameters at runtime via the HiltWorkerFactory.
Which Hilt scope keeps a single instance alive across configuration changes such as rotation, but not for the entire app?
- @ActivityScoped keeps one instance only until rotation ends
- @FragmentScoped keeps one instance for a fragment's lifetime
- @Singleton keeps one instance alive for the entire app process
- @ActivityRetainedScoped keeps one instance through rotation
Answer: @ActivityRetainedScoped keeps one instance through rotation
@ActivityRetainedScoped lives in the ActivityRetainedComponent, which survives configuration changes; @ActivityScoped is recreated on rotation and @Singleton lasts the whole app.
Which statement about how Hilt's annotations are handled in a modern (2026) Android build is correct?
- Hilt resolves the graph at runtime via reflection, with no processor
- Hilt only works with kapt and cannot be used with KSP builds
- Hilt generates code at build time and supports KSP like Dagger
- Hilt code generation happens later during R8 shrinking and minify
Answer: Hilt generates code at build time and supports KSP like Dagger
Hilt (over Dagger) generates and validates code at compile time, and Dagger/Hilt support KSP, which is the recommended faster processor over the older kapt.
A Fragment is annotated with @AndroidEntryPoint. What does Hilt require of the Activity that hosts it?
- The host Activity must also be annotated with @AndroidEntryPoint
- The host Activity must extend a special HiltActivity base class
- Nothing; the Fragment is injected independently of its Activity
- The host Activity must be annotated with @HiltAndroidApp instead
Answer: The host Activity must also be annotated with @AndroidEntryPoint
A Hilt Fragment can only be hosted by a Hilt-enabled Activity, so the host Activity must also carry @AndroidEntryPoint; @HiltAndroidApp belongs only on the Application.