架构:接口契约、职责边界与迁移路径)
文档教程知识库【免费下载链接】developer-roadmapInteractive roadmaps, guides and other educational content to help developers grow in their careers.项目地址https://gitcode.com/GitHub_Trending/de/developer-roadmap点击查看免费下载MVPModel-View-Presenter是 Android 生态中极具影响力的 UI 架构模式Presenter 作为 View 与 Model 之间的中介者View 将用户操作委托给 Presenter再由 Presenter 通过接口契约驱动 View 完成界面更新。本指南以 developer-roadmap 仓库中 Android 路线图的 MVP 节点 为核心骨架结合仓库中 MVC、MVVM、MVI、测试与依赖注入等相邻节点的定位帮助你完整掌握 MVP 的三层职责划分、接口契约设计、单元测试价值以及它为何在 MVVM/ViewModel 成为推荐方案后仍值得理解。MVP 是什么三层职责的精确划分从仓库的 MVP 文档 可以看到MVP 的核心定义可以拆解为三个要点Presenter 是中介者mediator它既不直接操作 UI 控件也不直接读写数据源而是负责接收 View 的委托、调用 Model、再把结果翻译回 View 可渲染的状态。View 只做委托与渲染View 把用户点击、输入等动作原样抛给 Presenter自己不包含任何业务判断Presenter 处理完成后通过接口契约interface contract回调 View 完成更新。接口契约是纽带View 与 Presenter 之间不是直接持有具体实现而是依赖一个双方共同定义的接口这是 MVP 可测试性的根基。这与仓库中其他架构节点的定位形成对照。在 MVC 节点 中明确指出Android 的 Activity/Fragment 常常同时充当 View 与 Controller导致传统 MVC 难以干净落地MVP 正是为解决这一问题而生——Activity/Fragment 只保留View身份把控制逻辑全部上收到 Presenter。一个可运行的 MVP 最小实现MVP 在 Kotlin/Android 中的经典落地形态如下以下为通用 MVP 结构的示意实现便于你在自己的项目中套用第一步定义接口契约Contractinterface LoginContract { interface View { fun showLoading() fun hideLoading() fun showError(message: String) fun navigateToHome() } interface Presenter { fun onLoginClicked(username: String, password: String) fun onDestroy() } }第二步实现 Presenter持有 View 接口与业务层Modelclass LoginPresenter( private val view: LoginContract.View, private val loginRepository: LoginRepository // Model 层 ) : LoginContract.Presenter { override fun onLoginClicked(username: String, password: String) { view.showLoading() loginRepository.login(username, password, onSuccess { view.hideLoading() view.navigateToHome() }, onFailure { error - view.hideLoading() view.showError(error.message ?: 登录失败) } ) } override fun onDestroy() { // 清理回调引用避免内存泄漏 } }第三步Activity/Fragment 作为 View实现接口并持有 Presenterclass LoginActivity : AppCompatActivity(), LoginContract.View { private lateinit var presenter: LoginContract.Presenter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_login) // 典型做法View 创建 Presenter并把 this 作为 View 契约传入 presenter LoginPresenter( view this, loginRepository LoginRepository() ) findViewByIdButton(R.id.btn_login).setOnClickListener { val username usernameInput.text.toString() val password passwordInput.text.toString() presenter.onLoginClicked(username, password) } } override fun showLoading() { /* 显示进度条 */ } override fun hideLoading() { /* 隐藏进度条 */ } override fun showError(message: String) { /* 弹出错误提示 */ } override fun navigateToHome() { /* 跳转首页 */ } }这套结构的关键收益在于LoginActivity中不再有登录逻辑的分支判断只保留把控件状态映射到接口方法的机械工作所有可验证的业务逻辑都集中在LoginPresenter中。接口契约为什么是 MVP 的灵魂View 通过接口契约被 Presenter 更新是 MVP 与 MVC 最本质的差异。接口契约带来的两个直接好处View 可以任意替换只要实现LoginContract.View无论是 Activity、Fragment 还是自定义 ViewPresenter 一律不关心。这使得同一套 Presenter 可以驱动多套界面例如手机竖屏/横屏布局差异。View 可以被伪造测试时传入一个实现了同一接口的FakeViewPresenter 完全感知不到差异从而可以在无 UI、无模拟器的纯 JVM 环境中跑单元测试。这与仓库中 Testing 节点 强调的JUnit 负责业务逻辑单元测试、Espresso 负责 UI 交互测试的分工天然契合——MVP 让业务逻辑测试与UI 测试彻底解耦。Presenter 的生命周期与内存泄漏防线MVP 的一个著名陷阱是内存泄漏如果 Presenter 通过接口持有了 Activity而异步回调在 Activity 销毁后才返回就会发生泄漏。仓库 activity-lifecycle 节点 与 viewmodel-state 节点 所描述的配置变更旋转屏幕场景正是 MVP 的痛点。常见的应对手段包括在onDestroy中调用presenter.onDestroy()让 Presenter 主动丢弃对 View 的强引用或置空弱引用在 View 重新创建后重新绑定新实例使 Presenter 内部状态得以保留这一思路后来被 ViewModel 以系统级方案解决也正是 MVP 被 MVVM 逐步取代的重要原因之一。仓库的 MVVM 节点 对此有明确交代Google 通过 ViewModel、LiveData、StateFlow 为 MVVM 提供官方支持View 以响应式方式观察 ViewModel 暴露的状态——这正是 MVP手动接口回调模式的现代化替代。与 MVC、MVVM、MVI 的定位对比仓库的 Design Architecture 节点 将 MVC、MVI、MVP、MVVM 统称为数据层、逻辑层、UI 层的多种交互方式并强调架构不是放之四海皆准的刚性结构而是可调整的指南。各模式在 Android 语境下的典型差异模式关键机制View 与逻辑层的关系仓库中的定位MVCController 处理输入Activity 常同时充当 View Controller职责混杂MVC 节点MVPPresenter 中介 接口契约回调View 只渲染逻辑全部在 Presenter依赖接口MVP 节点MVVMViewModel 暴露状态View 响应式观察View 观察状态自动更新单向依赖更松散MVVM 节点MVIIntent → Model → 不可变 State → View严格单向数据流状态可预测、易测试MVI 节点可以看到MVP 处于一个承上启下的位置它比 MVC 更清晰地分离了 View 与逻辑但又比 MVVM 更手动——没有系统级的生命周期感知也没有响应式数据管道。MVI 则把 MVP 的每次动作手动回调进一步抽象为不可变状态的单向流动常与 Kotlin Flow 和 Jetpack Compose 搭配使用。MVP 的取舍何时值得使用综合仓库多个节点的描述MVP 的优劣势可以归纳如下优势可测试性极强Presenter 依赖接口而非具体 View业务逻辑可在纯 JVM 环境用 JUnit 覆盖无需启动模拟器职责边界清晰View 只做渲染与委托Model 只做数据访问Presenter 独占业务编排代码可读性与可维护性明显提升与依赖注入天然契合仓库的 Dependency Injection 节点 提到 Dagger、Hilt、Koin 等框架负责管理依赖的创建与生命周期——Presenter 及其依赖Repository 等正是典型的可注入对象注入后测试时可以轻松替换为 Mock。代价与局限每屏都要维护 View/Presenter 两份接口样板代码较多Presenter 生命周期需自行管理旋转屏幕等配置变更场景易踩内存泄漏的坑交互逻辑散落在各回调方法中界面越复杂Presenter 越膨胀这一短板后来被 MVI 的状态机模型解决。结合仓库 Repository Pattern 节点 的实践一个高质量 MVP 项目通常会再叠加 Repository 层Presenter 不直接碰网络与数据库而是向 Repository 请求数据Repository 负责整合远端 API、本地缓存等数据源让 Presenter 只面对数据从哪来之外的纯业务问题。实践建议MVP 并非过时无用的模式。当项目需要极致的单测覆盖 极简依赖例如核心业务库、工具类应用、或团队希望在不引入响应式框架的前提下强制分层时MVP 依然是可靠选项而对于大多数面向 Google 推荐架构的新项目仓库文档的结论是 MVVM ViewModel 已成为推荐方案MVP 更多作为理解 Android 架构演进脉络、阅读历史代码库时的必备知识。延伸阅读MVP 文档本主题原始出处Android 架构与设计模式总览MVC 架构对比MVVM 架构与 ViewModel 官方支持MVI 架构与单向数据流Repository 模式数据源隔离Android 测试体系JUnit 与 Espresso依赖注入Dagger / Hilt / Koin赞分享文档教程知识库【免费下载链接】developer-roadmapInteractive roadmaps, guides and other educational content to help developers grow in their careers.项目地址https://gitcode.com/GitHub_Trending/de/developer-roadmap点击查看免费下载相关推荐ByT5-large实战指南10个技巧优化多语言翻译和文本生成ByT5 large实战指南10个技巧优化多语言翻译和文本生成 ByT5 large是一款强大的多语言文本生成模型基于T5架构优化而来特别擅长处理跨语言翻IronClaw Reborn 运行时选择契约RuntimeKind、SandboxBackend 与 CapabilityHost 的职责边界IronClaw Reborn 运行时选择契约RuntimeKind、SandboxBackend 与 CapabilityHost 的职责边界 IronCl人工智能AI 应用交互助手AI AgentRVC语音转换WebUI新手指南10分钟音频5分钟跑出你的专属变声器RVC语音转换WebUI新手指南10分钟音频5分钟跑出你的专属变声器 游戏开黑、直播连麦时想换一副声音却不想折腾复杂的音频处理工具RVCRetriev人工智能AI 应用语音音频深度学习上一篇使用 Kill Switch Scopes 示例掌握 agent-governance-toolkit 的三级作用域熔断机制下一篇Sentence Transformers 模型选型与实战指南从 MiniLM 到领域模型的全链路 Embedding 方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考