Dependency injection with Dagger 2
Dependency injection is the technique where an object does not create its own dependencies but receives them from the outside. Dagger 2 is the most common DI framework for Android, and its defining trait is that it assembles the whole dependency graph at compile time, generating plain Kotlin/Java code with no reflection at all. Hence its speed and the absence of runtime surprises.
There are three traps here, all about misunderstanding who is responsible for what. A @Module describes HOW to create objects, while a @Component wires modules into a graph and exposes the result. @Binds and @Provides both declare a binding, but @Binds is leaner. And multibinding does not override bindings — it collects them into a collection. The full map lives in the layers below.
Topic map
- Component and Module — a
@Modulesupplies recipes, a@Componentwires them into a graph and serves as the injection entry point. - Binds and Provides — a concrete factory
@Providesversus an abstract@Bindsthat maps an interface to an implementation. - Multibinding —
@IntoSetand@IntoMapcollect the contribution of many modules into one injectableSet/Map.
Common traps
| Mistake | Consequence |
|---|---|
Swapping the roles of @Component and @Module | A wrong mental model — you will not wire the graph correctly |
| Thinking Dagger builds the graph by reflection at runtime | You miss that everything is generated at compile time — errors show up immediately |
Writing a @Provides body that just returns its parameter | An extra no-op factory where a @Binds fits better |
Making a @Binds method concrete | It will not compile — @Binds must be abstract |
| Thinking multibinding overrides bindings | It actually aggregates them into a Set/Map, discarding nothing |
Not listing a @Module in a @Component | The module never enters the graph — the dependency is not found |
Interview relevance
The topic is asked to check whether you separate "how to create" (the module) from "how to wire and expose" (the component), and whether you understand that Dagger is a code generator, not a runtime container. A candidate who says "a @Component is an interface from which Dagger generates the graph implementation at compile time" gets ahead of "well, it's where the annotations hang".
Typical checks:
- The roles of
@Componentand@Moduleand why a module must be listed in a component. - The difference between
@Bindsand@Providesand when each is leaner. - That Dagger generates code at compile time rather than resolving by reflection.
- Why multibinding is needed and that it aggregates rather than overrides.
Common wrong answer: "Dagger assembles singletons into a shared registry by reflection at runtime". In fact the graph is code generated at compile time (DaggerAppComponent), and an unresolved dependency becomes a build error, not a runtime crash.