I just copied the Hilt setup from a Medium post and now everything works… kinda?”
Sound familiar? You’re not alone.
The Problem
Dependency Injection (DI) is not a “setup once and forget” tool. Yet that’s how many Android devs treat it — slap in Hilt, paste some boilerplate, sprinkle a few @Injects and call it architecture.
This mindset leads to:
- Fragile codebases
- Silent crashes
- Poor testability
- Misunderstood scopes
Copy-Paste DI is Dangerous
Let’s break down why blindly copying DI setups (especially Hilt/Dagger) is risky.
- You Probably Don’t Understand Scoping**** kotlin
@Singleton
class AnalyticsTracker @Inject constructor() { ... }
Looks innocent, right? But where is @singleton scoped to? The Application component? An Activity?
If you don’t explicitly bind scopes to the right lifecycle, you might hold onto context longer than you should, leaking memory or breaking navigation.
- You’re Injecting Into Everything DI is not just about removing new. Over-injecting leads to:
- Tightly coupled classes
- Hidden dependencies
- Poor separation of concerns
Instead:
- Use constructor injection where it makes sense
- Consider manual DI in small modules or test cases
- You’re Not Leveraging the Real Benefits Proper DI can:
- Replace dependencies for testing (mocking APIs, databases)
- Enforce SOLID principles
- Encourage loosely coupled, modular architecture
But you won’t get these benefits unless you understand:
- Component hierarchies
- Scope lifecycles
- Assisted injection
A Smarter Approach
- Start Small Before pulling in Hilt or Koin, understand manual DI. Try this:
class UserRepository(private val api: UserApi) { ... }
val api = Retrofit.Builder()...build().create(UserApi::class.java)
val repo = UserRepository(api)
This helps you appreciate what DI frameworks do under the hood.
Read the Docs, Not Just Blog Posts
Most copy-paste setups stem from secondhand tutorials that oversimplify. The official Hilt documentation is well-maintained and critical to avoid outdated practices.Use DI Strategically
- Use constructor injection for core dependencies.
- Use @Binds / @Provides only when needed.
- Avoid @AndroidEntryPoint on every screen — use ViewModel injection + factory patterns instead.
Bonus: When to Not Use a DI Framework
- Tiny apps or protos: Manual DI = less overhead.
- Modules like analytics or logging: Static classes might suffice.
- Heavy custom logic: Factory patterns are more transparent.
Even tools like NativBridge that help abstract native code dependencies should be integrated thoughtfully,understanding their DI implications before wiring them into your app’s core.
Let DI work for you, not against you.
Your Turn
- Do you use Hilt, Koin, or manual DI?
- Have you ever run into problems from copy-pasted setups?
- Drop a comment — let’s talk architecture, not just annotations .
Top comments (2)
Been there, just copying stuff and hoping for the best. Makes me wanna go back and really learn the why next time.
Been guilty of that copy-paste life for DI before, not gonna lie. Way better when I actually slowed down and learned how it works.