跪拜 Guibai
← All articles
Android

DI Isn't About Saving `new` — It's About Who Owns the Dependency Graph

By 潜龙勿用之化骨龙 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Without centralized dependency management, a growing Android codebase accumulates creation logic in every layer, so a constructor change or a new environment-specific implementation forces edits across dozens of files. DI moves that assembly work into a single configuration surface, which is the difference between a one-line swap and a multi-day refactor.

Summary

Direct object creation works fine in small Android projects. A ViewModel instantiating a Repository is simple and clear. The trouble starts when business classes begin assembling their own dependency chains — a LoginViewModel that builds Retrofit, configures a base URL, and wires up a UserApi has stopped caring about login logic and started caring about infrastructure. Constructor changes ripple through every creation site, and swapping implementations means hunting down every `new` call. DI frameworks like Hilt or Koin invert that control: a class declares what it needs, and the framework resolves the full object graph, deciding which implementation to supply and managing its lifecycle. The shift is from business code owning creation decisions to architecture owning them, which keeps responsibilities clean as the dependency graph grows from a handful of nodes to hundreds.

Takeaways
Direct instantiation with `new` or constructor calls is harmless in small projects but becomes a liability as dependency chains deepen.
When a ViewModel starts constructing Retrofit, configuring base URLs, and wiring up APIs, business logic and infrastructure concerns have merged.
The core problem is not object creation itself but managing the dependency graph — who depends on whom, who implements what, and what lifecycle each object needs.
DI inverts control: business code declares what interface it needs, and the framework decides which concrete implementation to supply and how to build it.
Constructor parameter changes propagate to every manual creation site; a DI module absorbs that change in one place.
Swapping implementations for testing, caching, or environment-specific behavior requires no business-code changes when classes depend on interfaces resolved by DI.
A practical signal to adopt DI is when a single class starts managing creation of its own Retrofit instance, database, API, and repository simultaneously.
Conclusions

The argument frames DI as an organizational boundary rather than a convenience — it's about separating the question 'what do I need?' from 'how is it built?', which is a more durable mental model than 'DI saves typing.'

Framing the problem as 'who owns the dependency graph' rather than 'how to create objects' explains why teams resist DI early and adopt it late: the pain is invisible until the graph is large enough that a single change breaks multiple files.

The post implicitly argues that DI's value scales non-linearly with project size — negligible at 5 classes, indispensable at 50, and a hard requirement at 500 — which matches the experience of teams that defer DI adoption until a refactor forces it.

Concepts & terms
Inversion of Control (IoC)
A design principle where the flow of control is inverted compared to procedural programming: instead of application code calling into a framework, the framework calls into application code. In DI, it means business code no longer decides which concrete implementation to create; the framework makes that decision and supplies it.
Object Dependency Graph
The full network of objects in an application and their 'depends on' relationships — e.g., a ViewModel depends on a UseCase, which depends on a Repository, which depends on an API and a database. Managing this graph centrally is what DI frameworks do.
DI Module (Hilt/Koin)
A configuration class annotated with @Module (Hilt) or declared as a module (Koin) that tells the DI framework how to construct and supply specific types. It centralizes creation logic so that constructor changes or implementation swaps happen in one place.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗