Hilt Scopes & Components Quiz
ARCHITECTURE › Dependency Injection
A binding has no scope annotation. What happens each time it is requested?
- Hilt reuses one cached instance for the whole app
- Hilt throws a compile-time error requiring a scope
- Hilt creates a new instance every time
- Hilt reuses one instance per Activity
Answer: Hilt creates a new instance every time
By default all Hilt bindings are unscoped, so Hilt creates a fresh instance on every request rather than caching one.
Which component's lifetime survives a configuration change such as a screen rotation?
- ActivityRetainedComponent, which lives through config changes
- ActivityComponent, which is recreated when the activity rotates
- FragmentComponent, which is torn down and rebuilt with the fragment
- ViewComponent, which belongs only to a single view instance
Answer: ActivityRetainedComponent, which lives through config changes
ActivityRetainedComponent is created at the first Activity#onCreate and destroyed at the last onDestroy, persisting across configuration changes; ActivityComponent and its children are recreated.
A dependency is annotated @ViewModelScoped. Two distinct ViewModel instances request it. What do they get?
- The same shared instance across both ViewModels
- A new instance on every single injection point
- An instance shared only if both are in the same Activity
- Each ViewModel gets its own single instance
Answer: Each ViewModel gets its own single instance
@ViewModelScoped shares one instance across all dependencies within a single ViewModel, but each separate ViewModel instance receives its own distinct instance.
You want exactly one instance of a repository shared across multiple ViewModels on the same screen flow but not the whole app. Best scope?
- Use @ViewModelScoped to share one repo within a single ViewModel.
- Use @ActivityRetainedScoped to share one repo across ViewModels.
- Use @FragmentScoped to share one repo across all fragments here.
- Use @ViewScoped to keep one repo instance for the entire app.
Answer: Use @ActivityRetainedScoped to share one repo across ViewModels.
@ActivityRetainedScoped shares one instance across ViewModels (which live under ActivityRetainedComponent) and survives config changes, without making it an app-wide singleton.
Which is the most likely consequence of scoping a class that holds an Activity Context to @Singleton?
- Faster injection because the instance is cached
- A compile error from Hilt's scope validation
- The Activity is leaked because the Singleton outlives it
- The Context is automatically swapped for the app Context
Answer: The Activity is leaked because the Singleton outlives it
A Singleton lives for the entire process, so holding an Activity Context keeps the destroyed Activity in memory, causing a leak; an application Context or narrower scope avoids it.
Which Hilt component provides @HiltViewModel ViewModels and shares the ViewModel's lifecycle?
- ViewModelComponent, scoped to the ViewModel lifecycle
- ActivityComponent, tied to the host Activity lifecycle
- SingletonComponent, tied to the whole Application
- FragmentComponent, tied to the host Fragment
Answer: ViewModelComponent, scoped to the ViewModel lifecycle
Hilt ViewModels are provided by the ViewModelComponent, which follows the same lifecycle as the ViewModel and can survive configuration changes.
A binding is installed only in ActivityComponent. From where can it be injected?
- From the SingletonComponent, so anywhere in the app
- From ViewModelComponent and ActivityRetainedComponent too
- From any sibling component such as ServiceComponent
- From ActivityComponent and its Fragment/View children
Answer: From ActivityComponent and its Fragment/View children
A binding is visible to its own component and any child below it in the hierarchy, so an ActivityComponent binding reaches Fragment and View components but not parents or siblings.
Which annotation and component pair correctly caches a single instance for the lifetime of a bound Service?
- @ServiceScoped on a module installed in ServiceComponent
- @ActivityScoped on a module installed in ActivityComponent
- @Singleton on a module installed in ServiceComponent
- @ServiceScoped on a module installed in SingletonComponent
Answer: @ServiceScoped on a module installed in ServiceComponent
ServiceComponent holds @ServiceScoped bindings, created at the Service's onCreate and destroyed at its onDestroy, so the cached instance matches the Service lifetime.
You need a Context that lives for the whole app and is safe to hold in a @Singleton. Which Hilt-predefined qualifier do you inject?
- @ActivityContext Context tied to one Activity only
- @ApplicationContext Context for the app's lifetime
- @AppContext Context for app scope, but not a Hilt qualifier
- @Singleton Context scoped for DI, not a Hilt Context qualifier
Answer: @ApplicationContext Context for the app's lifetime
Hilt predefines @ApplicationContext (the application Context) and @ActivityContext; the application Context outlives any Activity, so storing it in a Singleton causes no leak.
A Hilt @Module is written with @Provides methods but no @InstallIn annotation. What is the outcome?
- It is installed in SingletonComponent by default
- It compiles but its bindings are silently ignored at runtime
- Compilation fails because @InstallIn must be declared
- It is installed into every Hilt component automatically
Answer: Compilation fails because @InstallIn must be declared
Hilt requires every module to declare its component with @InstallIn; omitting it is a build error (only suppressible with @DisableInstallInCheck for special test cases).
A module installed in SingletonComponent declares a binding annotated @ActivityScoped. What happens?
- The binding silently falls back to unscoped behaviour
- The binding is quietly promoted to a @Singleton
- It works fine because scope annotations are only advisory
- A compile-time error: scope doesn't match the component
Answer: A compile-time error: scope doesn't match the component
A scope annotation must be one the install component actually supports; @ActivityScoped is not valid in SingletonComponent, so Hilt fails the build.
A @AndroidEntryPoint BroadcastReceiver needs an injected dependency. Receivers have no generated Hilt component, so from where are their members injected?
- SingletonComponent
- A dedicated BroadcastReceiverComponent
- ActivityComponent
- ServiceComponent
Answer: SingletonComponent
Hilt does not generate a component for BroadcastReceiver; it performs members injection directly from the SingletonComponent.
A custom View annotated @AndroidEntryPoint must access bindings scoped to its host Fragment. What is required?
- Annotate the binding @ViewScoped and install it in ViewComponent
- Add @WithFragmentBindings so it uses ViewWithFragmentComponent
- Inject the Fragment manually, because Views cannot use Hilt at all
- Install the module in ActivityComponent instead of a fragment scope
Answer: Add @WithFragmentBindings so it uses ViewWithFragmentComponent
@WithFragmentBindings makes the entry-point View use ViewWithFragmentComponent, which can see Fragment-scoped bindings; a plain ViewComponent only reaches Activity-level bindings.
You must obtain a Hilt binding inside a ContentProvider, which Hilt cannot annotate as a normal @AndroidEntryPoint. What is the idiomatic approach?
- Use field injection with a plain @Inject on the provider class
- Perform a runtime Hilt.getComponent() component lookup call
- Use an @EntryPoint interface via EntryPointAccessors
- It is impossible unless the class is turned into an Activity
Answer: Use an @EntryPoint interface via EntryPointAccessors
For classes outside Hilt's standard entry points, you define an @EntryPoint-annotated interface installed in the right component and fetch bindings through EntryPointAccessors.