Describe Hilt's component hierarchy and scope injection rules

Tests whether you understand Hilt's generated component tree and scoping rules. A strong answer lists the hierarchy, explains parent-outlives-child semantics, and states that ActivityScoped-into-Singleton injection fails at compile time.
What's really being asked
This question probes whether you understand that Hilt is not magic but a code generator that maps Dagger components onto the Android lifecycle. The interviewer cares if you can reason about object lifetime, memory safety, and the directionality of dependency graphs. Senior candidates should demonstrate that they see scoping as a contract about lifespan, not just a performance optimization or a namespace.
The full answer
First, enumerate the standard generated hierarchy in order: SingletonComponent at the root, followed by ActivityRetainedComponent, then ActivityComponent, then FragmentComponent, then ViewComponent, plus ViewWithFragmentComponent which sits under FragmentComponent. Second, explain the structural rule: every component is a subcomponent of its parent, meaning parents outlive children and dependencies can only flow downward. Third, clarify why this structure exists: it mirrors Android's own lifecycle tree so that when an activity is destroyed, its component and all scoped objects under it can be garbage collected without leaking backward into the application singleton. Fourth, answer the injection consequence directly: attempting to inject an ActivityScoped object into a Singleton-scoped object is a compile-time error because Hilt's annotation processor validates scope compatibility; a Singleton lives for the application lifetime and cannot safely hold a reference to something bound to a shorter-lived activity.
The mistakes people make
A major red flag is saying the code would compile and leak at runtime. Hilt fails the build because the scope hierarchy is enforced by the Dagger compiler, not checked at runtime. Another red flag is conflating ActivityRetainedComponent with ActivityComponent; the retained component survives configuration changes while the activity component does not, so their scoped objects have different lifetimes. A third red flag is suggesting you can work around the restriction by using a Provider or Lazy wrapper; while Provider can defer instantiation, it does not change scope compatibility, and Hilt still rejects the binding graph.
What usually comes next
The interviewer may ask how to share activity-level data with a singleton without breaking scope. The correct pattern is to use a factory or assisted injection so the singleton creates short-lived objects on demand rather than holding them. They may also ask about custom components; a strong answer notes that Hilt allows custom components but they must still fit into the existing parent-child tree and obey the same lifetime rules. Another follow-up is the difference between ActivityScoped and ActivityRetainedScoped; the retained scope survives rotation but dies when the user finishes the activity, whereas the non-retained scope dies on every configuration change.
A concrete example
Imagine a UserRepository annotated with Singleton that tries to inject an ActivityNavigator annotated with ActivityScoped. The UserRepository might cache data in a Map and live for hours, but the ActivityNavigator holds a reference to the current Activity. If Hilt allowed this, rotating the phone would destroy the activity yet the singleton repository would keep the old Activity instance alive, causing a massive memory leak. Hilt prevents this at compile time by rejecting the binding, forcing you to either scope the navigator higher, lower the repository scope, or pass the navigator as a method argument when needed.
Interview question
In Hilt, what happens when a Singleton-scoped class declares a direct dependency on an ActivityScoped type?
- a.It compiles if the ActivityScoped type is wrapped in a Provider or Lazy to defer instantiation
- b.Hilt's annotation processor fails the build because a longer-lived scope cannot depend on a shorter-lived scopeCorrect
- c.It compiles successfully but leaks memory at runtime when the activity is destroyed
- d.The ActivityScoped dependency is silently promoted to Singleton scope to match the requesting class
Why? this is the answer
Hilt enforces parent-outlives-child semantics at compile time, so the annotation processor rejects a Singleton holding a direct reference to an ActivityScoped object. The tempting distractor that it would compile and leak at runtime is wrong because Hilt fails the build before runtime, and wrapping the dependency in Provider or Lazy does not bypass scope compatibility.
Just read this? Test yourself on what you have been reading.
Read the original → developer.android.com
- #android
- #hilt
- #dependency-injection
- #dagger
- #memory-management
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on android — each one lists the topics its interview covers.
See open roles