Hilt Scopes & Components Interview Questions

ARCHITECTURE › Dependency Injection

In your own words, what's the actual purpose of scoping a binding in Hilt, is it primarily a performance optimization, or something else? Walk me through a bug that happens when someone scopes something for the wrong reason.

What a strong answer covers: Scoping is primarily about instance identity and shared, consistent state within a bounded lifetime, not a performance shortcut. A classic bug is scoping a class to @Singleton purely to 'avoid recreating it,' which then leaks an Activity Context, holds stale references, or lets unrelated screens accidentally observe each other's mutable state; the fix is to scope only when a shared instance across a specific lifetime is genuinely required, and otherwise leave the binding unscoped so each consumer gets its own fresh, isolated instance.

Two ViewModels for different screens in the same flow both need to see the same in-flight form data. Walk me through which Hilt scope you'd use and why plain @ViewModelScoped won't work.

What a strong answer covers: @ViewModelScoped gives each individual ViewModel instance its own fresh copy, so two different ViewModels never actually share the same object even though both are 'ViewModel scoped.' To share state across ViewModels in one flow, you scope the shared holder to @ActivityRetainedScoped (or hoist it into a nav-graph-scoped ViewModel), since ActivityRetainedComponent survives configuration changes and is the parent that each screen's ViewModelComponent hangs off; the trap is assuming ViewModel scope means 'shared across ViewModels' when it actually means one-per-ViewModel.

Walk me through what's actually happening in Dagger's generated component hierarchy when you get an error about a binding being installed in the wrong component, say a ViewModelScoped binding that code injected via ActivityComponent can't see. What's the underlying rule?

What a strong answer covers: Hilt's components form a strict parent-to-child tree, so a child component can see everything its ancestors provide, but a parent can never reach into a descendant's bindings. ViewModelComponent hangs off ActivityRetainedComponent in parallel to ActivityComponent rather than being its child, so a binding scoped to ViewModelComponent is invisible from ActivityComponent; the fix is moving the binding up to a component that is genuinely an ancestor of every site that needs it, not just assuming 'it's close enough in the hierarchy.'

Back to Hilt Scopes & Components