首页/新闻资讯/正文详情

Android 项目架构设计:从 MVC 到 MVI 的演进与实践

发布时间:2026/11/5 14:39:42 来源:云帆数科 栏目:资讯中心
Android 项目架构设计:从 MVC 到 MVI 的演进与实践
引言在 Android 应用开发中一个清晰、可维护、可测试的架构设计是项目成功的关键。随着应用复杂度的提升和团队规模的扩大选择合适的架构模式变得至关重要。本文将带你深入浅出地了解 Android 项目架构设计的演进历程、主流模式对比以及如何在实际项目中落地实践。1. 架构设计的重要性为什么我们需要关注架构代码可维护性清晰的架构让代码结构一目了然新成员能快速上手老成员能高效定位问题。可测试性良好的架构天然支持单元测试、集成测试确保代码质量。团队协作模块化的设计允许不同开发者或团队并行开发减少冲突。可扩展性当业务需求变化或增加新功能时良好的架构能最小化改动成本实现平滑扩展。单一职责每个组件、类甚至方法都有明确的职责避免出现“上帝类”或“面条式代码”。一个没有良好架构的应用随着时间推移往往会变成难以维护的“遗留代码”任何改动都可能引发意想不到的 Bug。2. 经典架构模式演进Android 架构并非一成不变它随着开发理念和工具链的进步而不断演进。2.1 MVC (Model-View-Controller)模型 (Model)负责数据和业务逻辑。视图 (View)负责 UI 展示在 Android 中通常是Activity/Fragment和 XML 布局。控制器 (Controller)负责处理用户输入更新模型和视图。在 Android 早期Activity/Fragment常常身兼 View 和 Controller 两职。问题Activity/Fragment过于臃肿承担了太多职责生命周期、UI 更新、业务逻辑、数据获取导致难以测试和维护也就是常说的“上帝对象”。2.2 MVP (Model-View-Presenter)为了解决 MVC 中 View 和 Controller 耦合过紧的问题MVP 模式被引入。模型 (Model)不变负责数据和业务逻辑。视图 (View)变为被动接口只定义 UI 更新的方法。Activity/Fragment实现此接口。表示层 (Presenter)作为 View 和 Model 的中间人持有 View 的引用从 Model 获取数据处理业务逻辑并调用 View 接口的方法来更新 UI。优点将 UI 逻辑从Activity/Fragment中抽离使其变得更薄便于单元测试 Presenter。缺点Presenter 持有 View 的强引用需要小心处理生命周期避免内存泄漏。同时随着业务复杂Presenter 也可能变得庞大。2.3 MVVM (Model-View-ViewModel)借助 Jetpack 组件特别是LiveData和DataBinding/ViewBindingMVVM 成为 Android 官方推荐架构。模型 (Model)负责数据和业务逻辑。视图 (View)Activity/Fragment负责设置 UI 和观察 ViewModel 的数据变化。视图模型 (ViewModel)持有 UI 相关的数据并通过LiveData/StateFlow暴露给 View。它不持有 View 的引用因此与生命周期无关。优点数据驱动 UIView 订阅 ViewModel 的数据流数据变化自动驱动 UI 更新。生命周期感知ViewModel和LiveData自动管理生命周期避免内存泄漏。更好的关注点分离View 只负责展示和用户交互ViewModel 负责准备展示数据。// 一个简单的 ViewModel 示例classUserViewModel(privatevaluserRepository:UserRepository):ViewModel(){privateval_userNameMutableLiveDataString()valuserName:LiveDataString_userNamefunloadUser(userId:String){viewModelScope.launch{valuseruserRepository.getUser(userId)_userName.valueuser.name}}}2.4 MVI (Model-View-Intent)MVI 是一种响应式架构强调单向数据流和状态不可变性。模型 (Model)代表状态 (State)。UI 是所有状态的函数。视图 (View)渲染状态并将用户输入转换为意图 (Intent)发送。意图 (Intent)代表用户或系统发起的动作如按钮点击、初始化。处理器通常由 ViewModel 担任接收 Intent处理业务逻辑并生成新的 State。优点单向数据流数据流向清晰可预测便于调试和追溯状态变化。状态不可变任何时候 State 都是确定的避免了因状态共享和异步修改带来的竞态问题。易于测试业务逻辑集中在处理 Intent 和生成新 State 的过程中易于进行单元测试。// MVI 状态与意图示例dataclassLoginState(valisLoading:Booleanfalse,valisSuccess:Booleanfalse,valerrorMessage:String?null)sealedclassLoginIntent{objectInit:LoginIntent()dataclassLogin(valusername:String,valpassword:String):LoginIntent()objectDismissError:LoginIntent()}3. 现代分层架构设计单一的 MV* 模式不足以支撑大型复杂应用。现代 Android 项目通常采用清晰的分层架构结合 MVVM 或 MVI 作为表现层模式。3.1 典型分层一个健壮的分层架构通常包含以下层次渲染错误:Mermaid 渲染失败: Parse error on line 2: ... subgraph A[表现层 (Presentation Layer) ----------------------^ Expecting SQE, DOUBLECIRCLEEND, PE, -), STADIUMEND, SUBROUTINEEND, PIPE, CYLINDEREND, DIAMOND_STOP, TAGEND, TRAPEND, INVTRAPEND, UNICODE_TEXT, TEXT, TAGSTART, got PS表现层 (Presentation Layer)组件Activity,Fragment,ViewModel,ComposeUI。职责处理 UI 展示和用户交互。使用 MVVM 或 MVI 模式。依赖领域层Use Cases。领域层 (Domain Layer)组件Use Cases (Interactors), Repository Interfaces。职责封装核心、独立的业务规则。它是应用中最稳定的一层不应依赖 Android SDK 或任何框架。依赖无纯 Kotlin/Java 模块。数据层 (Data Layer)组件Repository Implementations, Data Sources (Local/Remote), Data Models。职责管理应用数据提供统一的数据访问入口。实现领域层定义的 Repository 接口。依赖领域层接口以及各种 SDK如 Room, Retrofit。3.2 依赖规则关键原则依赖方向永远指向抽象接口并且向内指向核心领域层。表现层依赖领域层的 Use Cases。数据层实现领域层定义的 Repository 接口。领域层不依赖任何其他层保持纯净。4. 组件化与模块化对于大型团队和项目单一的 App 模块会带来编译慢、职责模糊、团队协作冲突等问题。组件化/模块化是解决方案。4.1 概念模块化 (Modularization)将代码拆分为多个 Gradle 模块:core:network,:feature:login。每个模块可以独立编译明确依赖关系。组件化 (Componentization)在模块化的基础上强调业务功能的独立性和可复用性。每个业务组件如:feature:home可以独立开发、测试甚至理论上能独立运行。4.2 常见模块划分app/ (主App模块负责组装) ├── feature/ (功能模块) │ ├── login/ │ ├── home/ │ └── profile/ ├── core/ (核心基础模块) │ ├── network/ │ ├── database/ │ ├── common/ (通用扩展、工具) │ └── design/ (UI组件、主题) └── domain/ (领域模块纯Kotlin) ├── model/ └── repository/4.3 组件间通信页面跳转使用 Deep Link 或路由框架如 App Startup 自研路由或第三方库。数据传递通过接口暴露服务。可以使用 Service Locator 模式或依赖注入框架如 Hilt/Dagger来管理组件间的依赖。避免循环依赖通过抽取公共接口到:core:api模块等方式解决。5. 实战构建一个组件化 MVVM 项目假设我们要构建一个简单的用户信息展示应用。5.1 项目结构MyApp/ ├── app/ (空壳负责依赖注入和组装) ├── core/ │ ├── network/ (Retrofit 配置) │ ├── database/ (Room 配置) │ └── common/ ├── domain/ │ ├── model/ (User) │ └── repository/ (UserRepository 接口) ├── data/ │ └── repository/ (UserRepository 实现) └── feature/ └── userprofile/ ├── di/ (该功能的 Hilt Module) ├── presentation/ (Activity, ViewModel, State) └── UserProfileFeature.kt5.2 关键代码示例1. Domain Layer (纯 Kotlin)// domain/model/User.ktdataclassUser(valid:String,valname:String,valemail:String)// domain/repository/UserRepository.kt (接口)interfaceUserRepository{suspendfungetUser(id:String):User}2. Data Layer (实现接口)// data/repository/UserRepositoryImpl.ktclassUserRepositoryImplInjectconstructor(privatevaluserService:UserService,// Retrofit 接口privatevaluserDao:UserDao// Room Dao):UserRepository{overridesuspendfungetUser(id:String):User{// 业务逻辑优先缓存网络获取后更新缓存returnuserDao.getUser(id)?:fetchFromNetwork(id)}privatesuspendfunfetchFromNetwork(id:String):User{...}}3. Presentation Layer (MVVM with State)// feature/userprofile/presentation/UserProfileViewModel.ktHiltViewModelclassUserProfileViewModelInjectconstructor(privatevalgetUserUseCase:GetUserUseCase// UseCase 封装了业务逻辑):ViewModel(){privateval_uiStateMutableStateFlow(UserProfileState())valuiState:StateFlowUserProfileState_uiState.asStateFlow()funloadUser(userId:String){viewModelScope.launch{_uiState.update{it.copy(isLoadingtrue)}try{valusergetUserUseCase(userId)_uiState.update{it.copy(isLoadingfalse,useruser)}}catch(e:Exception){_uiState.update{it.copy(isLoadingfalse,errore.message)}}}}}// feature/userprofile/presentation/UserProfileState.ktdataclassUserProfileState(valisLoading:Booleanfalse,valuser:User?null,valerror:String?null)6. 架构选择建议与总结新手或小型项目从MVVM开始。它学习曲线平缓有强大的官方组件ViewModel, LiveData支持能解决大部分生命周期和数据绑定问题。中型至大型项目采用分层架构 MVVM/MVI。引入清晰的领域层和数据层为模块化打下基础。如果状态管理变得复杂可以考虑引入 MVI 来获得更可预测的数据流。超大型团队项目必须推进组件化/模块化。结合单一职责和依赖倒置原则使用 Hilt/Dagger 进行依赖注入管理模块间通信。记住没有“银弹”架构。最好的架构是适合你的团队规模、项目复杂度和迭代速度的架构。核心目标是控制复杂度提升代码的可读性、可测试性和可维护性。架构设计是一个持续演进的过程随着 Kotlin Multiplatform、Jetpack Compose 等新技术的普及未来的架构模式也必将有新的发展。保持学习灵活应用。

相关推荐

【办公类-16-02】20220923“2022上学期 大班运动场地分配表1-跳过节日循环排序”(python 排班表系列)
【办公类-16-02】20220923“2022上学期 大班运动场地分配表1-跳过节日循环排序”(python 排班表系列)

样例展示:跳过节日的运动场地循环排序表(8个班级8组内容) 背景需求: 复工复学后,周计划做起来!每周的运动场地安排照旧…… 存在问题(一): 8个大班,靠着人工排序,每周都要推算一次这个规则,推演麻烦,且容易出错 (1)每周都要打开前一周教案看写到哪一个场地, (… · 2026/11/5 14:39:42

k7沙箱创建与配置:从YAML文件到高级安全策略
k7沙箱创建与配置:从YAML文件到高级安全策略

k7沙箱创建与配置:从YAML文件到高级安全策略 【免费下载链接】k7 Your own self-hosted infra for lightweight VM sandboxes to safely execute untrusted code. CLI, API, Python SDK. ⭐ Star it if you like it! ⭐ 项目地址: https://gitcode.com/gh_mirrors… · 2026/9/18 22:01:38

如何轻松下载国家中小学智慧教育平台电子课本:tchMaterial-parser的完整指南
如何轻松下载国家中小学智慧教育平台电子课本:tchMaterial-parser的完整指南

如何轻松下载国家中小学智慧教育平台电子课本:tchMaterial-parser的完整指南 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具,帮助您从智慧教育平台中获取电子课本的 PDF 文件网址并进行下载,让您更方便地获取… · 2026/10/3 9:20:21

ADS122U04IPWR+STM32F427ZI工业级温度测量信号链设计
ADS122U04IPWR+STM32F427ZI工业级温度测量信号链设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 14:10:41

UART接口24位ADC搭配RS485,解决远距离温度监控难题
UART接口24位ADC搭配RS485,解决远距离温度监控难题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 14:10:41

UART接口24位ADC搭配PIC18F46K22的RTD与热电偶测温实践
UART接口24位ADC搭配PIC18F46K22的RTD与热电偶测温实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 14:10:41

GD32E10x官方例程入门:从GPIO点灯到串口调试
GD32E10x官方例程入门:从GPIO点灯到串口调试

简介:这份GD32E10x系列官方例程面向嵌入式硬件与单片机开发者,基于ARM Cortex-M3内核,汇集兆易创新GD32E10x的示例代码,适合工业控制、消费电子、通信设备等场景的学习、验证与二次开发。压缩包共935个文件,约11.16MB&… · 2026/11/5 13:52:29

基于Django的运维平台实战:资产、发布、巡检、告警一体化
基于Django的运维平台实战:资产、发布、巡检、告警一体化

简介:这份资源是一套基于Django框架开发的运维平台源码,面向具备Python基础、希望了解Web运维系统实现思路的开发者与运维人员,可用于学习主机管理、服务监控、日志查看、任务调度、权限控制、资源统计、脚本执行与故障告警等常见运维模块的落… · 2026/11/5 13:49:27

基于ADS122U04IPWR与STM32F427ZI的工业测温方案设计
基于ADS122U04IPWR与STM32F427ZI的工业测温方案设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 13:22:54

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:07

多智能体协作系统架构设计与实践优化
多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39

大模型系统性入门实战指南:从原理到部署微调的全链路路线
大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39

鸿蒙文件系统沙箱机制解析与开发实践
鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:07

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码