Dagger Fundamentals & Manual DI Quiz

ARCHITECTURE › Dependency Injection

What does Dagger generate when you annotate an interface with @Component?

Answer: A concrete component implementation and factories for its types

Dagger generates a concrete implementation of the @Component interface at build time, along with factory classes for each type, with no reflection involved.

Which scenario is the WEAKEST case for adopting Hilt?

Answer: Kotlin Multiplatform shared code or a small library module

Hilt is Android-specific and ties into Android components, so it's a poor fit for KMP shared modules, standalone libraries, or tiny apps where manual constructor injection suffices.

When must you use a @Module with @Provides instead of constructor @Inject?

Answer: When binding an interface or third-party type like Retrofit

You can't put @Inject on the constructor of an interface or a third-party class, so a @Provides (or @Binds) method in a module tells Dagger how to supply it.

What is the primary purpose of a qualifier annotation like @Named in Dagger?

Answer: To distinguish bindings that share the same type

Qualifiers disambiguate two or more bindings that share the same Java/Kotlin type so Dagger knows which one to inject at a given site.

A key benefit of Dagger validating the graph at compile time is that:

Answer: Missing dependencies and cycles fail the build, not at runtime

Dagger walks the graph at build time, ensuring every dependency is satisfiable and cycle-free, so errors surface at compilation rather than as runtime exceptions.

How does Koin differ from Hilt/Dagger in how it reports a missing dependency?

Answer: Koin throws at runtime when the dependency is resolved

Koin is a runtime service locator using a Kotlin DSL, so an unregistered dependency surfaces only when it is resolved at runtime, unlike Dagger's compile-time check.

In manual DI, what best describes the AppContainer pattern?

Answer: A class on the Application that centralizes shared dependencies

AppContainer is a regular class (not a singleton object) stored on the Application; it centralizes construction and sharing of app-wide dependencies, with flow containers handling shorter-lived scopes.

Why is @Binds generally preferred over @Provides when mapping an interface to a single implementation?

Answer: @Binds needs no method body, so Dagger generates leaner, faster code

@Binds is an abstract method that simply tells Dagger an impl satisfies an interface, so no method body is generated and the result is more efficient than a concrete @Provides method.

What does annotating a binding with @Singleton actually guarantee?

Answer: One instance reused for the lifetime of its @Singleton component

A Dagger scope ties an instance's lifetime to its component, not the whole process; @Singleton on the application component means one shared instance for that component's lifetime, and a different component would hold its own.

You have a legitimate cyclic dependency where A needs B and B needs A. What is the idiomatic Dagger way to break the cycle so the graph compiles?

Answer: Inject Provider<T> or Lazy<T> on one side to defer creation

Dagger fails the build on a direct cycle, but wrapping one dependency in Provider<T> or Lazy<T> defers its creation until first use, breaking the construction-time loop.

In a @Component.Factory or @Component.Builder, what does @BindsInstance let you do?

Answer: Bind a runtime object, like an Application or userId, into the graph

@BindsInstance on a builder/factory parameter feeds an externally created object (like a Context, Application, or runtime value) into the dependency graph instead of having Dagger construct it.

Which Dagger feature lets several different modules each contribute an element into one injected Set or Map?

Answer: Multibindings with @IntoSet, @ElementsIntoSet, and @IntoMap

Multibindings let modules across the codebase each add entries to a collection that Dagger aggregates into a single injectable Set<T> or Map<K, V>, a common pattern for plugin-style registries.

A class needs both Dagger-provided dependencies and a runtime parameter known only at creation time. Which Dagger feature fits best?

Answer: Assisted injection with @AssistedInject and a factory

Assisted injection mixes graph-provided dependencies with caller-supplied @Assisted parameters; Dagger generates a factory you inject and call with the runtime value to build the instance.

In a modern 2026 Android build, how do Dagger and Hilt produce their factory and component code?

Answer: By a compile-time annotation processor, using KSP or KAPT

Dagger and Hilt are codegen frameworks that run an annotation processor at compile time; modern projects use the faster KSP backend, with KAPT remaining as the legacy option, and no runtime reflection is involved.

Back to Dagger Fundamentals & Manual DI