Android MVP架构包声明正确方式及DI全局化配置合理性咨询
Hey there! Let's tackle your two questions about Android MVP architecture and DI setup—both are key to building a maintainable app, so great call asking about this.
There are two widely accepted, practical ways to structure your packages in MVP, each with its own sweet spot depending on your project size:
Option 1: Feature-Based Package Organization (Recommended for Medium/Large Projects)
This approach groups all MVP components related to a single business feature into one package. It’s fantastic for keeping code modular and easy to maintain as your app grows.
Example structure:
com.yourapp ├── login │ ├── LoginActivity.kt (View layer) │ ├── LoginPresenter.kt │ ├── LoginContract.kt (Defines View/Presenter interfaces) │ └── LoginRepository.kt (Model layer) ├── home │ ├── HomeFragment.kt (View) │ ├── HomePresenter.kt │ ├── HomeContract.kt │ └── HomeRepository.kt ├── common │ ├── base │ │ ├── BasePresenter.kt │ │ └── BaseView.kt │ └── utils └── di (Your global DI component)
- Pros: Strong feature independence—you can work on the login flow without jumping between 3+ packages. It also makes future modularization (like moving to a componentized architecture) way easier.
- Cons: For tiny apps, it might feel like overkill with too many small packages, but this is a minor tradeoff for scalability.
Option 2: Layer-Based Package Organization (Great for Small Projects)
If your app is small and has only a few features, grouping by MVP layers (View, Presenter, Model) keeps things simple and easy to grasp for new team members.
Example structure:
com.yourapp ├── views │ ├── LoginActivity.kt │ └── HomeFragment.kt ├── presenters │ ├── LoginPresenter.kt │ └── HomePresenter.kt ├── models │ ├── LoginRepository.kt │ └── HomeRepository.kt ├── contracts │ ├── LoginContract.kt │ └── HomeContract.kt ├── common │ ├── base │ └── utils └── di
- Pros: Super clear for beginners—you know exactly where all Presenters or Views live. Works great when you only have a handful of features.
- Cons: As your app scales, each layer package gets bloated. Finding all components for a single feature means jumping between 3-4 different packages, which slows down maintenance.
Absolutely—this is not just reasonable, it’s the recommended approach.
Here’s why:
- DI (like Dagger/Hilt) is an infrastructure tool, not part of the MVP’s View/Presenter/Model layers. Its job is to manage dependencies across your entire app, so keeping it as a global component makes sense.
- Global DI lets all MVP layers access shared dependencies (like network clients, database instances, or global repositories) without duplicating setup code. For example, your LoginPresenter can get a
UserRepositoryvia constructor injection, and your HomeFragment can inject its Presenter directly—all powered by the global DI setup.
A few best practices to keep in mind:
- For large apps, split your DI into global and feature-specific components. This prevents your main DI component from becoming a bloated "god object" while still keeping shared dependencies global.
- Stick to single responsibility: Let the global DI handle app-wide dependencies (e.g., OkHttpClient, Room database), and feature-specific DI handle local dependencies (e.g., a login-only API service wrapper).
内容的提问来源于stack exchange,提问作者Tushar Pandey

