APP架构揭秘:从分层到MVVM实战
一、先看全局一个 APP 由哪些部分组成用户看到的只是手机上的界面背后其实是一整套系统┌─────────────────────────────────────────────────────┐ │ 手机客户端APP │ │ 界面层 → 业务逻辑层 → 数据层网络 / 本地存储 │ └──────────────────────────┬──────────────────────────┘ │ HTTPS / WebSocket ▼ ┌─────────────────────────────────────────────────────┐ │ 服务端 │ │ 接入层网关、负载均衡→ 业务服务 → 数据库 / 缓存 │ └──────────────────────────┬──────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────┐ │ 第三方服务 │ │ 推送、支付、地图、短信、CDN、统计分析、崩溃监控 │ └─────────────────────────────────────────────────────┘“APP 架构”通常讨论两件事1. 客户端内部怎么组织代码 ← 本文重点 2. 客户端和服务端怎么配合二、客户端的分层架构几乎所有现代 APP 都按职责分成三层┌──────────────────────────────┐ │ 表现层UI Layer │ 显示界面、响应点击 │ 页面、控件、ViewModel │ └──────────────┬───────────────┘ │ 调用 ┌──────────────▼───────────────┐ │ 领域层Domain Layer可选 │ 纯业务规则 │ UseCase下单、计算优惠 │ └──────────────┬───────────────┘ │ 调用 ┌──────────────▼───────────────┐ │ 数据层Data Layer │ 数据从哪里来 │ Repository │ │ ├─ 远程网络 API │ │ └─ 本地数据库、缓存、文件 │ └──────────────────────────────┘每层的规则层负责不该做表现层把数据显示出来把用户操作传下去直接发网络请求、写数据库领域层业务规则满 30 减 5、库存校验关心界面长什么样、数据存在哪数据层决定数据从网络拿还是从缓存拿关心数据怎么显示依赖方向只能向下上层知道下层下层不知道上层。这样换一套界面或者换一个数据库其他层都不用改。举例外卖 APP 点“下单”用户点「提交订单」 │ ▼ 表现层OrderViewModel.submit() │ 显示 loading ▼ 领域层PlaceOrderUseCase │ 校验地址、计算优惠后的价格 ▼ 数据层OrderRepository.createOrder() │ 调用服务端接口 POST /orders │ 成功后写入本地数据库方便离线查看 ▼ 结果一路返回 → 表现层跳转到支付页面三、常见架构模式MVC / MVP / MVVM / MVI这些模式解决的是表现层内部怎么分工的问题。MVCModel - View - ControllerView ◀──▶ Controller ──▶ ModeliOS 早期的默认模式问题Controller 又管界面又管逻辑代码越写越多被戏称为“Massive View Controller”MVPModel - View - PresenterView ◀──接口──▶ Presenter ──▶ ModelView 只负责显示逻辑全在 PresenterPresenter 通过接口操作 View方便单元测试问题接口很多样板代码多MVVMModel - View - ViewModel—— 目前主流View ──观察数据绑定──▶ ViewModel ──▶ Model ◀────状态变化自动刷新──ViewModel 不持有 View只暴露“状态”View 观察状态状态一变界面自动刷新AndroidJetpack、iOSSwiftUI、Flutter 都主推这种思路MVIModel - View - IntentView ──用户意图(Intent)──▶ ViewModel ──▶ 新状态(State) ──▶ View └────────────── 单向循环 ──────────────────┘整个页面只有一个状态对象数据单向流动状态可预测便于调试和回放和 React / Redux 的思想一致对比模式复杂度可测试性现在的使用情况MVC低差小项目、老项目MVP中好部分老 Android 项目MVVM中好主流MVI较高很好声明式 UICompose、SwiftUI中越来越多MVVM 示例Kotlin Jetpack Compose// 页面状态dataclassOrderUiState(valloading:Booleanfalse,valerror:String?null,valorderId:String?null)// ViewModel只管状态不碰界面classOrderViewModel(privatevalplaceOrder:PlaceOrderUseCase):ViewModel(){privateval_stateMutableStateFlow(OrderUiState())valstate:StateFlowOrderUiState_statefunsubmit(cart:Cart)viewModelScope.launch{_state.valueOrderUiState(loadingtrue)_state.valuetry{OrderUiState(orderIdplaceOrder(cart))}catch(e:Exception){OrderUiState(error下单失败请重试)}}}// View只根据状态显示ComposablefunOrderScreen(vm:OrderViewModel){valstatebyvm.state.collectAsState()when{state.loading-CircularProgressIndicator()state.error!null-Text(state.error!!)state.orderId!null-Text(下单成功${state.orderId})}}Clean Architecture整洁架构在大型项目中常把上面的分层进一步严格化┌──────────────────────┐ │ 框架层UI、数据库、网络 │ │ ┌────────────────┐ │ │ │ 接口适配层 │ │ │ │ ┌────────────┐ │ │ │ │ │ 业务用例 │ │ │ │ │ │ ┌────────┐ │ │ │ │ │ │ │ 业务实体 │ │ │ │ ← 最核心不依赖任何框架 │ │ │ └────────┘ │ │ │ │ │ └────────────┘ │ │ │ └────────────────┘ │ └──────────────────────┘ 依赖方向只能从外向内核心业务代码不依赖 Android/iOS 系统可以独立测试甚至在多个平台复用。四、技术选型原生、跨平台、混合方案代表技术优点缺点适合原生AndroidKotliniOSSwift性能最好系统能力最全两套代码两支团队大厂核心 APP、性能要求高跨平台Flutter、React Native一套代码两端运行接近原生体验部分系统功能需写原生插件中小团队、快速迭代共享逻辑Kotlin Multiplatform业务逻辑共享界面各自原生生态较新想兼顾性能和复用混合 / H5WebView H5、小程序可随时更新不用发版性能和体验较差活动页、运营页面实际中大型 APP 往往是混合的┌─────────────────────────────────────┐ │ 首页、核心流程 → 原生性能好 │ │ 部分业务模块 → Flutter / RN │ │ 活动页、规则页 → H5随时改 │ └─────────────────────────────────────┘五、大型 APP模块化 / 组件化当团队有几十上百人时所有代码放在一个工程里会出现编译慢、互相改冲突、改一处坏一片。于是拆成模块┌──────────────────────────────────────────────┐ │ 壳工程App │ 只负责组装 └───────┬──────────┬──────────┬──────────┬──────┘ ▼ ▼ ▼ ▼ ┌──────────┐┌──────────┐┌──────────┐┌──────────┐ │ 首页模块 ││ 订单模块 ││ 用户模块 ││ 支付模块 │ 业务模块 └────┬─────┘└────┬─────┘└────┬─────┘└────┬─────┘ 互相不直接依赖 └───────────┴─────┬─────┴───────────┘ ▼ ┌──────────────────────────────────────────────┐ │ 基础组件网络、图片加载、存储、日志、路由、UI 库 │ └──────────────────────────────────────────────┘关键问题业务模块之间怎么通信不能直接引用对方的类否则又耦合在一起。常用方式1. 路由用 URL 跳转页面 Router.open(app://order/detail?id123) 2. 接口下沉把接口定义放在公共层实现放在各模块 公共层interface UserService { fun isLogin(): Boolean } 用户模块实现它 订单模块通过服务发现拿到实现并调用 3. 事件总线发布 / 订阅消息如“登录成功”谨慎使用好处每个团队负责自己的模块可以单独编译、单独调试。六、客户端和服务端怎么配合APP │ ▼ CDN ─────────────── 图片、视频、安装包等静态资源 │ ▼ API 网关 ─────────── 鉴权、限流、路由、协议转换 │ ▼ BFF为前端服务的后端 ── 把多个服务的数据聚合成一个页面需要的格式 │ ▼ 业务微服务用户服务 │ 订单服务 │ 商品服务 │ 支付服务 │ ▼ 缓存Redis 数据库MySQL 等 消息队列几个常见设计设计说明BFF首页需要用户、商品、优惠券三份数据BFF 合并成一个接口减少手机请求次数服务端驱动 UI服务端下发页面配置JSONAPP 按配置渲染不发版也能改首页布局长连接聊天、实时订单状态用 WebSocket 等长连接推送APP 不在前台时通过 APNs苹果/ 厂商通道安卓推送消息七、贯穿所有层的通用能力除了业务代码一个成熟 APP 还需要这些基础设施1. 网络层- 统一封装请求、错误处理、登录过期自动刷新 token - 超时重试注意下单等操作要防止重复提交 - 弱网 / 丢包下的处理和上一节内容相关 - 接口缓存先显示缓存再请求最新数据2. 本地存储数据类型存储方式简单配置是否首次启动SharedPreferences / DataStore / UserDefaults结构化数据聊天记录、订单SQLite、Room、Core Data、Realm敏感信息token、密码Android Keystore / iOS Keychain图片、文件文件系统 磁盘缓存3. 离线优先Offline First界面只读本地数据库 ◀── 数据层负责和服务端同步 │ 有网后台同步最新数据写入数据库界面自动刷新 没网照样能看历史数据操作先存本地联网后再上传4. 安全- 全部使用 HTTPS必要时做证书校验SSL Pinning - 敏感数据加密存储不在日志中打印 - 代码混淆、防篡改、防调试 - 关键逻辑价格计算、权限判断放在服务端客户端不可信5. 性能- 启动速度延迟初始化非必要的 SDK - 列表流畅复用列表项、图片按尺寸加载和前面 DPR 的知识相关 - 内存避免内存泄漏大图及时回收 - 包体积资源压缩、按需下载6. 监控与发布- 崩溃监控Firebase Crashlytics、Bugly 等 - 性能监控卡顿、启动耗时、网络耗时 - 埋点统计用户行为分析 - 灰度发布新版本先给 5% 用户 - 功能开关 / AB 测试服务端控制功能是否开启出问题可随时关闭 - 热更新H5、RN、Flutter 的部分内容可不经应用商店更新需遵守平台规则八、架构的演进不要一开始就过度设计阶段 1个人 / 小项目 MVVM Repository一个工程 够用就好 阶段 2小团队、功能变多 加入领域层UseCase、依赖注入Hilt / Koin / Swinject 统一网络、存储、日志等基础组件 阶段 3大团队、多业务线 模块化 / 组件化、路由 跨平台框架、动态化、完善的监控和灰度体系原则架构是为了解决当前的问题而不是为了“看起来高级”。总结1. 整体客户端 服务端 第三方服务 2. 客户端分三层表现层 → 领域层 → 数据层依赖只能向下 3. 表现层模式MVC → MVP → MVVM主流→ MVI单向数据流 4. 技术选型原生 / 跨平台 / H5大型 APP 常常混合使用 5. 大型项目要模块化模块之间通过路由和接口通信 6. 服务端常见CDN、API 网关、BFF、微服务、推送 7. 通用能力网络、存储、离线、安全、性能、监控、灰度发布 8. 架构随项目规模演进不要过度设计一句话好的 APP 架构就是让每段代码只做一件事、只依赖它该依赖的东西这样项目变大时依然改得动、测得了、跑得快。

相关新闻

渗透测试报告自动化:数据模型与渲染流水线实践指南

渗透测试报告自动化:数据模型与渲染流水线实践指南

简介:渗透测试报告工具pentest-report面向安全团队与渗透测试工程师,将项目与参与跟踪、范围定义、自动扫描、结果记录和报告导出整合为统一工作流,可显著减少手动重复扫描与报告排版的投入。工具内置多种常见扫描动作,可对Web服务…

2026/10/15 20:17:51 阅读更多 →
Flutter演示项目Forge:从计数器Demo到实战踩坑的架构拆解

Flutter演示项目Forge:从计数器Demo到实战踩坑的架构拆解

1. 从 Demo 起步:为什么要拿“玩具项目”当真项目做先聊点实在的。Forge 这个名字听起来挺唬人,但它的起点其实就是个 Flutter 演示项目,最初就是官方模板里的计数器 Demo,再加几个随手写的示例页面。我当时给自己定的规矩很简单&…

2026/10/15 20:17:51 阅读更多 →
SuperDesign 开源 IDE 设计代理指南:用自然语言在 VS Code / Cursor / Windsurf 中生成 UI 与原型

SuperDesign 开源 IDE 设计代理指南:用自然语言在 VS Code / Cursor / Windsurf 中生成 UI 与原型

人工智能AI 应用AI Agent前端 【免费下载链接】superdesign AI Product Design Agent - Open Source 项目地址: https://gitcode.com/gh_mirrors/su/superdesign 点击查看 免费下载 SuperDesign 是一款运行在 IDE 内部的 AI 产品设计代理扩展:输入一句自…

2026/10/15 20:16:49 阅读更多 →

最新新闻

脑电信号模拟发生系统:为脑机接口测试打造可复现的基准数据

脑电信号模拟发生系统:为脑机接口测试打造可复现的基准数据

简介:面向脑机接口测试的高精度脑电信号模拟发生系统设计文档,聚焦医疗设备制造商、科研工作者与脑机接口开发团队的测试需求。方案针对传统信号发生器系统复杂、体积庞大、精度不足等问题,提出含数模转换、同相比例放大与信号衰减电路的模拟…

2026/10/16 0:33:22 阅读更多 →
2026年设计服务业人才建设报告:从郑中设计实践看前置化人才蓄水池构建路径

2026年设计服务业人才建设报告:从郑中设计实践看前置化人才蓄水池构建路径

核心要点摘要作为全球高端酒店与商业空间设计机构,郑中设计(CCD)在海内外项目推进中,面临传统招聘新人理论与工程落地脱节、内部带教成本高企的现实难题。为搭建新生代设计师人才蓄水池,企业开展多渠道调研评估&#x…

2026/10/16 0:29:21 阅读更多 →
电子元器件比价平台:4个真实比价渠道和方法

电子元器件比价平台:4个真实比价渠道和方法

元器件比价不能只看单价。同一颗料,不同平台的报价差异可达30%——但低价背后可能藏着翻新料、无检测、无售后的坑。真正靠谱的比价要同时比4样东西:单价、检测能力、账期、售后。比价渠道本身也要选对,用错渠道比出来的价格没有参考价值。一…

2026/10/16 0:28:21 阅读更多 →
成都GEO服务商梯队观察:带实体产业背景的,为什么更稀缺

成都GEO服务商梯队观察:带实体产业背景的,为什么更稀缺

很多企业主找GEO服务商时,习惯先看案例数和报价。但有一项底色比这些更关键:这家服务商自己有没有跑过真实的实体生意。它既关系到交付是否靠谱,也关系到企业会不会被带进合规泥潭。 先说清楚一个容易被混的概念。GEO优化的是AI助手在生成答案…

2026/10/16 0:28:21 阅读更多 →
银行流水NAATI翻译件怎么办理?递签前要准备什么?

银行流水NAATI翻译件怎么办理?递签前要准备什么?

办澳洲签证,银行流水常用来佐证资金能力,属于多页、数字密集的文件,翻译的重点不在文采,而在交易记录的逐行对应:日期、金额、币种、余额一个都不能错位。银行流水NAATI认证翻译可在线办理:上传银行盖章版流…

2026/10/16 0:28:21 阅读更多 →
WorkBuddy实战复盘:从零到上架Android应用的完整避坑指南

WorkBuddy实战复盘:从零到上架Android应用的完整避坑指南

1. 从零到上线:为什么我选择 WorkBuddy 作为主力开发工具去年年底我接了一个私活,客户要求两周内交付一个能上架安卓应用市场的工具类 App。预算不高,人手就我一个,后端还得自己搭。当时我评估了几条路线:纯原生 Andro…

2026/10/16 0:28:21 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

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

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/15 9:49:14 阅读更多 →