What is Dependency Injection and how is it used in Flutter?
Short Answer
Dependency Injection means a class receives its dependencies from the outside (via constructor or a container) instead of creating them itself, which decouples classes from concrete implementations and makes them easy to test with substitutes.
Without DI, a class might do `final repo = UserRepositoryImpl();` directly inside itself — now it's permanently coupled to that exact implementation and can't be tested without hitting a real API. With DI, the class instead declares `UserRepository repo` as a constructor parameter, and something else (a parent widget, a DI container, or a provider) decides which concrete implementation to hand it.
In Flutter, this is commonly done via Provider/Riverpod (providers are themselves a form of DI — they supply object instances to the widget tree) or a dedicated service locator like `get_it`, where you register implementations once (often at app startup) and retrieve them anywhere with `GetIt.instance<UserRepository>()`. The key benefit in tests: you register a fake implementation in the container before the test runs, and every class that depends on that interface transparently gets the fake instead of the real thing.
Common Mistakes
- ×Confusing a service locator (`get_it`) with true dependency injection — a service locator still has classes reaching out to grab their dependencies, just from a registry instead of constructing them; constructor injection is the stricter form.
- ×Registering dependencies in a way that creates circular dependencies between services.
Related Questions
What is Clean Architecture and how does it apply to Flutter?
Clean Architecture separates an app into independent layers — typically presentation, domain, and data — where inner layers (business logic) never depend on outer layers (UI, frameworks, databases), so business rules can be tested and reused independently of Flutter itself.
What is the Repository pattern?
The Repository pattern puts a single abstraction in front of however data is actually fetched or stored — network, local cache, database — so the rest of the app talks to one consistent interface and doesn't care where the data comes from.