tezvyn:

Manual Dependency Injection: No Frameworks, Just Code

AI-drafted, machine-checkedSource: developer.android.comintermediate
Manual Dependency Injection: No Frameworks, Just Code

Manual dependency injection means you are the 'framework,' creating and passing dependencies yourself via constructors. It's great for simple apps where a full DI library is overkill, but the footgun is creating dependencies inside the class that needs them.

WHY IT EXISTS To decouple components for better testability and maintainability without adding the complexity and build-time cost of a full dependency injection (DI) framework. It is the most fundamental implementation of the Inversion of Control principle.

THE MENTAL MODEL Think of it as passing ingredients to a chef. Instead of the chef going to the pantry to grab a specific brand of flour (creating their own dependency), you hand them the exact flour you want them to use (injecting the dependency). You control the dependencies from the outside.

HOW IT WORKS You provide dependencies to a class through its constructor; this is called constructor injection. The class that uses the dependency (e.g., a ViewModel) declares what it needs, but the class that creates it (e.g., an Activity using a ViewModelFactory) is responsible for creating and passing in those dependencies. For apps with more than a few dependencies, you can create manual 'container' classes that are responsible for building and providing the dependency graph for a given feature or flow.

WHEN TO USE IT Use manual DI for small projects, simple library modules, or when you want to avoid the learning curve and build-time overhead of DI frameworks like Hilt or Dagger. It's an excellent way to understand DI principles before adopting a framework, as the patterns are the same.

WHEN NOT TO USE IT Avoid it in large, complex applications with deep or wide dependency graphs. Manually wiring everything becomes tedious, error-prone, and creates a lot of boilerplate code. At that scale, a DI framework provides necessary automation, lifecycle management, and scoping that is difficult to replicate correctly by hand.

ONE CANONICAL EXAMPLE An Android ViewModel needs a UserRepository to fetch data. Instead of the ViewModel creating its own instance, its constructor requires one: class UserViewModel(private val userRepository: UserRepository). You then create a ViewModelProvider.Factory that knows how to instantiate the UserRepository and pass it into the UserViewModel's constructor when the system requests a new ViewModel instance. The Activity or Fragment gets the ViewModel via this factory, fully decoupled from how its dependencies are built.

Read the original → developer.android.com

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.