Appearance
07 架构对比
目录
1. 架构演进历史
1.1 Android 架构发展时间线
2008 年 ──┬── Android 发布,没有官方架构推荐
│
2012 年 ──┼── MVC 成为事实标准
│
2014 年 ──┼── MVP 开始流行 (Google I/O)
│
2015 年 ──┼── MVVM 正式发布 (ViewBinding, DataBinding)
│
2017 年 ──┼── Jetpack 发布,推荐 MVVM + Repository
│
2019 年 ──┼── Jetpack Compose 发布,MVI 开始流行
│
2021 年 ──┼── Clean Architecture 广泛采用
│
2023 年 ──┴── Multi-module + Clean Architecture + Compose1.2 为什么需要架构演进?
每个架构都是为了解决前一代的问题:
| 架构 | 解决的问题 | 引入的新问题 |
|---|---|---|
| MVC | 没有架构,代码混乱 | UI 与逻辑耦合严重 |
| MVP | UI 与逻辑耦合 | 接口过多,实现复杂 |
| MVVM | 接口过多 | 双向数据绑定性能问题 |
| MVI | 状态管理混乱 | 学习成本高 |
| Clean | 关注点不分离 | 代码量增加 |
2. MVC 架构详解
2.1 MVC 架构原理
┌─────┐ ┌─────┐ ┌─────┐
│Model│────▶│Controller│────▶│View│
└─────┘ └─────┘ └─────┘
▲ │ │
│ └───────────┘
│ │
└───────────────┘- Model: 数据和业务逻辑
- View: UI 展示
- Controller: 处理用户输入,更新 Model 和 View
2.2 MVC 在 Android 中的实现
kotlin
// Activity 扮演 Controller + View 的双重角色
class UserActivity : AppCompatActivity() {
// View 部分
private lateinit var userName: TextView
private lateinit var userEmail: TextView
private lateinit var refreshButton: Button
// Controller 部分
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
initializeViews()
setupListeners()
loadData()
}
// Model 部分(通常直接调用 API)
private fun loadData() {
apiService.getUser { user ->
runOnUiThread {
userName.text = user.name
userEmail.text = user.email
}
}
}
private fun setupListeners() {
refreshButton.setOnClickListener {
loadData() // 重复的加载逻辑
}
}
}2.3 MVC 的问题
MVC 在 Android 中的问题:
├── Activity 过于臃肿 (1000+ 行代码) ❌
├── 业务逻辑分散在各个 Activity ❌
├── 难以测试 ❌
├── 代码复用困难 ❌
├── 生命周期管理混乱 ❌
└── UI 状态难以管理 ❌2.4 MVC 适用场景
- 小型 Demo 项目
- 快速原型开发
- 简单的工具类应用
- 单个 Activity 的应用
3. MVP 架构详解
3.1 MVP 架构原理
┌─────┐
│View │──────┐
└─────┘ │
▼
┌─────┐ ┌─────┐
│Model│────▶│Presenter│
└─────┘ └─────┘
│
└────────┐
▼
更新 View 状态- View: 只负责 UI 展示,通过接口与 Presenter 交互
- Presenter: 处理业务逻辑,协调 View 和 Model
- Model: 数据层
3.2 MVP 在 Android 中的实现
kotlin
// 1. View 接口
interface UserView {
fun showLoading()
fun hideLoading()
fun showUser(user: User)
fun showError(message: String)
}
// 2. Presenter
class UserPresenter(
private val view: UserView,
private val repository: UserRepository
) {
fun getUser(userId: String) {
view.showLoading()
repository.getUser(userId) { result ->
when (result) {
is Result.Success -> {
view.hideLoading()
view.showUser(result.data)
}
is Result.Failure -> {
view.hideLoading()
view.showError(result.exception.message)
}
}
}
}
fun onDestroy() {
// 处理内存泄漏
}
}
// 3. Activity 实现 View 接口
class UserActivity : AppCompatActivity(), UserView {
private lateinit var presenter: UserPresenter
private lateinit var userName: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
presenter = UserPresenter(this, userRepository)
presenter.getUser("user123")
}
// View 接口实现
override fun showLoading() {
progressBar.visibility = View.VISIBLE
}
override fun hideLoading() {
progressBar.visibility = View.GONE
}
override fun showUser(user: User) {
userName.text = user.name
}
override fun showError(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
override fun onDestroy() {
super.onDestroy()
presenter.onDestroy() // 手动管理生命周期
}
}3.3 MVP 的优点
- ✅ 分离了 UI 和业务逻辑
- ✅ Activity 不再臃肿
- ✅ 易于单元测试
- ✅ 代码复用性提高
3.4 MVP 的缺点
MVP 的缺点:
├── 接口过多,每个 View 需要一个接口 ❌
├── Presenter 数量爆炸 ❌
├── 需要手动管理生命周期 ❌
├── 不支持响应式编程 ❌
├── 配置复杂,样板代码多 ❌
└── 切换 View 时Presenter需要重新创建 ❌3.5 MVP 适用场景
- 中等规模项目
- 需要一定测试覆盖
- 团队熟悉接口编程
- 不追求最新的架构模式
4. MVVM 架构详解
4.1 MVVM 架构原理
┌───────┐ ┌───────┐
│ View │◀───────▶│ViewModel│
└───────┘ 数据绑定 └───────┘
│
▼
┌───────────┐
│Repository │
└───────────┘- View: UI 层,通过数据绑定与 ViewModel 连接
- ViewModel: 管理 UI 状态,处理业务逻辑
- Model/Repository: 数据层
4.2 MVVM 在 Android 中的实现
kotlin
// 1. ViewModel
class UserViewModel @Inject constructor(
private val repository: UserRepository
) : ViewModel() {
private val _user = MutableLiveData<User>()
val user: LiveData<User> = _user
private val _loading = MutableLiveData<Boolean>()
val loading: LiveData<Boolean> = _loading
private val _error = MutableLiveData<String>()
val error: LiveData<String> = _error
fun getUser(userId: String) {
_loading.value = true
viewModelScope.launch {
try {
val user = repository.getUser(userId)
_user.value = user
_loading.value = false
} catch (e: Exception) {
_error.value = e.message
_loading.value = false
}
}
}
override fun onCleared() {
super.onCleared()
// ViewModel 自动管理生命周期
}
}
// 2. Activity/Fragment
class UserActivity : AppCompatActivity() {
private lateinit var viewModel: UserViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
viewModel = ViewModelProvider(this).get(UserViewModel::class.java)
// 观察 ViewModel 状态
viewModel.user.observe(this) { user ->
userName.text = user.name
}
viewModel.loading.observe(this) { isLoading ->
progressBar.visibility = if (isLoading) View.VISIBLE else View.GONE
}
viewModel.error.observe(this) { error ->
Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
}
// 加载数据
viewModel.getUser("user123")
}
}4.3 MVVM 的优点
MVVM 的优点:
├── 自动管理生命周期 ✅
├── 支持配置变更(如旋转屏幕)✅
├── 数据绑定简化了 UI 更新 ✅
├── 易于测试 ✅
├── 支持响应式编程 ✅
├── Google 官方推荐 ✅
└── 生态完善(Jetpack)✅4.4 MVVM 的缺点
MVVM 的缺点:
├── 双向数据绑定可能导致性能问题 ❌
├── 状态管理不够明确 ❌
├── 复杂的业务逻辑可能导致 ViewModel 臃肿 ❌
└── 学习 DataBinding/LiveData 需要时间 ❌4.5 MVVM 适用场景
- 大多数 Android 项目
- 需要处理复杂 UI 状态
- 团队希望使用官方推荐方案
- 需要良好的配置变更支持
5. MVI 架构详解
5.1 MVI 架构原理
┌───────┐ ┌───────┐ ┌───────┐
│ View │───────▶│ViewModel│──────▶│ Reduce│
└───────┘ Event └───────┘ Action └───────┘
▲ │
│ ▼
└────────────────────────── StateFlow ←──────────┘- Model: 不可变的 State
- View: 纯函数,State 的展示
- ViewModel: 处理 Event,返回 Action,更新 State
5.2 MVI 在 Android 中的实现
kotlin
// 1. 定义 State (不可变)
@JvmInline
value class UserScreenState(
val user: User? = null,
val isLoading: Boolean = false,
val error: String? = null
) {
companion object {
val Initial = UserScreenState()
}
}
// 2. 定义 Event
sealed class UserScreenEvent {
object LoadUser : UserScreenEvent()
object RefreshUser : UserScreenEvent()
data class UpdateName(val name: String) : UserScreenEvent()
}
// 3. ViewModel (处理 Event,返回 State Flow)
class UserViewModel @Inject constructor(
private val repository: UserRepository
) : ViewModel() {
private val _event = MutableSharedFlow<UserScreenEvent>()
val event: SharedFlow<UserScreenEvent> = _event.asSharedFlow()
val state: StateFlow<UserScreenState> = buildStateFlow()
private fun buildStateFlow(): StateFlow<UserScreenState> {
return _event
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5000),
UserScreenState.Initial
)
.scan(UserScreenState.Initial) { state, event ->
when (event) {
is UserScreenEvent.LoadUser -> {
state.copy(isLoading = true)
}
is UserScreenEvent.RefreshUser -> {
// 触发刷新
state
}
else -> state
}
}
}
fun onEvent(event: UserScreenEvent) {
viewModelScope.launch {
_event.emit(event)
}
}
private fun loadUser() {
viewModelScope.launch {
try {
val user = repository.getUser("user123")
_state.update { it.copy(user = user, isLoading = false) }
} catch (e: Exception) {
_state.update { it.copy(error = e.message, isLoading = false) }
}
}
}
}
// 4. Compose UI (纯函数)
@Composable
fun UserScreen(
state: UserScreenState,
onEvent: (UserScreenEvent) -> Unit
) {
when {
state.isLoading -> {
CircularProgressIndicator()
}
state.error != null -> {
ErrorView(message = state.error)
Button(onClick = { onEvent(UserScreenEvent.LoadUser) }) {
Text("Retry")
}
}
state.user != null -> {
UserDetail(user = state.user!!)
}
}
}5.3 MVI 的优点
MVI 的优点:
├── 单一数据源 (Single Source of Truth) ✅
├── 状态完全可预测 ✅
├── 易于调试和测试 ✅
├── 支持时间旅行调试 ✅
├── 与 Compose 完美配合 ✅
└── 状态变化可追溯 ✅5.4 MVI 的缺点
MVI 的缺点:
├── 学习曲线陡峭 ❌
├── 需要理解函数式编程 ❌
├── 代码量可能增加 ❌
├── 性能优化复杂 ❌
└── 不适合简单场景 ❌5.5 MVI 适用场景
- 使用 Jetpack Compose 的项目
- 复杂的状态管理需求
- 团队有函数式编程经验
- 对调试和测试有较高要求
6. VIPER 架构详解
6.1 VIPER 架构原理
┌───────┐
│ View │──────┐
└───────┘ │
▼
┌───────┐ ┌───────┐
│Interactor│◀──│Presenter│
└───────┘ └───────┘
│ │
▼ │
┌───────┐ │
│Entity │───────────┘
└───────┘
│
▼
┌───────┐
│Repository│
└───────┘- View: UI 展示
- Interceptor: 用户入口
- Presenter: 协调各个组件
- Interactor: 业务逻辑
- Entity: 领域实体
- Repository: 数据访问
6.2 VIPER 在 Android 中的实现
kotlin
// 1. Entity
data class UserEntity(
val id: String,
val name: String,
val email: String
)
// 2. Repository Interface
interface UserRepository {
suspend fun getUser(userId: String): UserEntity
}
// 3. Interactor
class GetUserInteractor(
private val repository: UserRepository
) {
suspend fun execute(userId: String): Either<Exception, UserEntity> {
return try {
val user = repository.getUser(userId)
Right(user)
} catch (e: Exception) {
Left(e)
}
}
}
// 4. Presenter
class UserPresenter(
private val interactor: GetUserInteractor,
private val view: UserView
) {
fun loadUser(userId: String) {
view.showLoading()
viewModelScope.launch {
when (val result = interactor.execute(userId)) {
is Right -> {
view.hideLoading()
view.showUser(result.value)
}
is Left -> {
view.hideLoading()
view.showError(result.value.message)
}
}
}
}
}
// 5. View Interface
interface UserView {
fun showLoading()
fun hideLoading()
fun showUser(user: UserEntity)
fun showError(message: String)
}
// 6. Activity (View + Interactor)
class UserActivity : AppCompatActivity(), UserView {
private lateinit var presenter: UserPresenter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val interactor = GetUserInteractor(userRepository)
presenter = UserPresenter(interactor, this)
presenter.loadUser("user123")
}
// View 接口实现
override fun showLoading() { /* ... */ }
override fun hideLoading() { /* ... */ }
override fun showUser(user: UserEntity) { /* ... */ }
override fun showError(message: String) { /* ... */ }
}6.3 VIPER 的优点
VIPER 的优点:
├── 职责分离非常明确 ✅
├── 每个组件都有单一职责 ✅
├── 易于测试 ✅
├── 代码组织清晰 ✅
└── 适合大型项目 ✅6.4 VIPER 的缺点
VIPER 的缺点:
├── 组件数量多,代码量大 ❌
├── 学习曲线非常陡峭 ❌
├── 对于简单功能过度设计 ❌
├── 文件数量爆炸 ❌
└── 团队协作成本高 ❌6.5 VIPER 适用场景
- 超大型项目
- 长期维护的项目
- 团队有架构设计经验
- 对代码质量要求极高
7. Clean Architecture
7.1 Clean Architecture 原理
┌─────────────────────────────────────┐
│ Presentation Layer │
│ (Activity, Fragment, ViewModel) │
├─────────────────────────────────────┤
│ Domain Layer │
│ (Entity, UseCase, Repository API) │
├─────────────────────────────────────┤
│ Data Layer │
│ (Repository Impl, DataSource) │
└─────────────────────────────────────┘7.2 Clean Architecture 的特点
- 以业务逻辑为中心
- 依赖倒置原则
- 框架独立
- 数据库独立
- UI 独立
7.3 Clean Architecture 与其他架构的关系
Clean Architecture 是一个框架,可以包含:
├── MVVM (Presentation 层)
├── Repository 模式 (Data 层)
├── Use Case (Domain 层)
└── 依赖注入 (跨层)8. 架构横向对比
8.1 综合对比表
| 特性 | MVC | MVP | MVVM | MVI | VIPER | Clean |
|---|---|---|---|---|---|---|
| 职责分离 | ⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 可测试性 | ⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 学习曲线 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐ | ⭐ | ⭐ |
| 代码量 | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐ | ⭐ |
| 灵活性 | ⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 生态支持 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| 官方推荐 | ❌ | ❌ | ✅ | ⚠️ | ❌ | ⚠️ |
8.2 代码对比
kotlin
// MVC - 所有逻辑在一个类
class UserActivity : AppCompatActivity() {
fun loadData() { /* API 调用 + UI 更新 */ }
}
// MVP - 分离 View 和 Presenter
interface UserView { /* View 接口 */ }
class UserPresenter(view: UserView) { /* 业务逻辑 */ }
class UserActivity : AppCompatActivity(), UserView { /* UI 实现 */ }
// MVVM - ViewModel 管理状态
class UserViewModel : ViewModel() {
val user = MutableLiveData<User>()
}
class UserActivity : AppCompatActivity() {
val viewModel: UserViewModel by viewModel()
}
// MVI - 不可变状态流
data class UserState(val user: User? = null)
class UserViewModel {
val state = StateFlow<UserState>(UserState())
}
// VIPER - 多个组件协作
class UserView
class UserPresenter
class UserInteractor
class UserRepository
class UserEntity
// Clean Architecture - 三层分离
class UserViewModel // Presentation
class GetUserUseCase // Domain
class UserRepositoryImpl // Data8.3 性能对比
| 架构 | 启动速度 | 内存占用 | 流畅度 |
|---|---|---|---|
| MVC | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| MVP | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| MVVM | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| MVI | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| VIPER | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| Clean | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
9. 架构选择指南
9.1 选择因素
选择架构时考虑:
├── 项目规模
├── 团队规模
├── 团队经验
├── 项目周期
├── 维护周期
├── 测试要求
├── 性能要求
└── 技术栈9.2 项目规模 vs 架构选择
| 项目规模 | 推荐架构 | 理由 |
|---|---|---|
| Demo/原型 | MVC | 快速开发,不需要复杂架构 |
| 小型项目 (❤️ 个月) | MVP / MVVM | 平衡开发效率和可维护性 |
| 中型项目 (3-12 个月) | MVVM + Repository | 官方推荐,生态完善 |
| 大型项目 (>12 个月) | MVVM + Clean | 清晰的分层,易于维护 |
| 超大型项目 | VIPER / Clean | 职责分离,易于扩展 |
9.3 团队经验 vs 架构选择
| 团队经验 | 推荐架构 | 理由 |
|---|---|---|
| 初级团队 | MVC / MVP | 学习曲线平缓 |
| 中级团队 | MVVM | 平衡复杂度和可维护性 |
| 高级团队 | MVI / Clean | 充分利用架构优势 |
| 专家级团队 | VIPER / Custom | 定制最佳架构 |
9.4 技术栈 vs 架构选择
| 技术栈 | 推荐架构 | 理由 |
|---|---|---|
| View + Retrofit | MVP / MVVM | 成熟的方案 |
| Compose | MVI / MVVM | 函数式编程友好 |
| Kotlin Coroutines | MVVM / MVI | 异步处理友好 |
| Hilt | MVVM / Clean | 依赖注入支持 |
10. 大厂架构实践
10.1 字节跳动
字节架构特点:
├── 模块化架构
├── MVVM + Clean Architecture
├── 自研框架 (Flutter 混合)
├── 组件化 + 插件化
└── 强类型 + 静态检查10.2 美团
美团架构特点:
├── 领域驱动设计 (DDD)
├── Clean Architecture
├── 多模块划分
├── 基础组件库
└── 数据埋点体系10.3 阿里巴巴
阿里架构特点:
├── 端云一体化
├── React Native / Flutter
├── 组件化架构
├── 业务中台化
└── 智能化 (AI 集成)10.4 腾讯
腾讯架构特点:
├── 自研框架 (TXIM, TXVideo)
├── 微前端架构
├── 混合开发 (Native + H5)
├── 性能优化极致
└── 游戏化体验10.5 大厂架构趋势
2024 年大厂架构趋势:
├── Jetpack Compose 全面采用 ✅
├── Multi-module 项目结构 ✅
├── Clean Architecture 主流 ✅
├── Kotlin 多平台 (KMP) ✅
├── 性能监控自动化 ✅
├── 测试覆盖率要求提高 ✅
└── AI 辅助开发 ✅11. 架构演进路线
11.1 个人技术成长路线
Level 1 (初级):
└── MVC -> 理解基本概念
Level 2 (中级):
└── MVP / MVVM -> 掌握分层思想
Level 3 (高级):
└── MVVM + Repository -> 掌握数据流
Level 4 (专家):
└── Clean Architecture -> 掌握架构设计
Level 5 (架构师):
└── 自定义架构 -> 根据场景定制11.2 项目架构演进路线
Phase 1 (MVP):
Activity + API 调用
↓
Phase 2 (分离):
Activity + Manager
↓
Phase 3 (MVP):
View + Presenter + Model
↓
Phase 4 (MVVM):
View + ViewModel + Repository
↓
Phase 5 (Clean):
Presentation + Domain + Data
↓
Phase 6 (模块化):
Multi-module + Feature 模块11.3 演进注意事项
架构演进注意事项:
├── 不要过度设计
├── 渐进式重构
├── 保持向后兼容
├── 测试先行
├── 团队共识
├── 文档同步
└── 性能监控12. 面试考点
12.1 基础概念题
Q1: 说说你了解的 Android 架构有哪些?
参考答案:
常见的 Android 架构:
1. MVC - Model-View-Controller
2. MVP - Model-View-Presenter
3. MVVM - Model-View-ViewModel
4. MVI - Model-View-Intent
5. VIPER - View-Interactor-Presenter-Entity-Repository
6. Clean Architecture
我主要使用 MVVM + Repository + Clean Architecture 的组合。Q2: MVVM 和 MVP 有什么区别?
参考答案:
主要区别:
1. 数据流: MVP 是单向,MVVM 是双向数据绑定
2. 生命周期: MVP 手动管理,MVVM 自动管理
3. 配置变更: MVP 需要处理,MVVM 自动处理
4. 测试: 都易于测试,但 MVVM 更简单
5. 学习曲线: MVP 平缓,MVVM 稍陡12.2 架构设计题
Q3: 如何设计一个支持离线功能的消息列表?
参考答案:
架构选择:MVVM + Repository + Clean
Domain 层:
- Message Entity
- GetMessageUseCase
- MessageRepository Interface
Data 层:
- MessageRepositoryImpl (缓存优先策略)
- LocalDataSource (Room)
- RemoteDataSource (Retrofit)
- Mapper
Presentation 层:
- MessageViewModel
- MessageListScreen
离线策略:
1. 优先显示本地数据
2. 后台同步服务器
3. 冲突解决策略
4. 离线消息队列Q4: 如何选择项目的架构?
参考答案:
考虑因素:
1. 项目规模
2. 团队经验
3. 维护周期
4. 性能要求
5. 技术栈
我的选择标准:
- 小项目:MVVM
- 中项目:MVVM + Repository
- 大项目:Clean Architecture
- Compose 项目:MVI12.3 实战问题
Q5: 你在项目中遇到过哪些架构问题?如何解决的?
参考答案模板:
问题:Activity 代码过多,难以维护
解决:提取 ViewModel,采用 MVVM 架构
问题:状态管理混乱
解决:引入 StateFlow,采用 MVI 模式
问题:数据源管理复杂
解决:引入 Repository 模式
问题:模块耦合严重
解决:采用 Clean Architecture 分层Q6: Clean Architecture 的优缺点是什么?
参考答案:
优点:
- 职责分离清晰
- 易于测试
- 技术替换方便
- 长期维护友好
缺点:
- 代码量增加
- 学习曲线陡峭
- 小项目可能过度设计
- 初期开发速度较慢
适用场景:
- 长期维护的项目
- 大型项目
- 团队有架构经验总结
选择架构不是选择"最好的",而是选择"最适合的"。
架构选择原则:
- 简单优先:能简单就不要复杂
- 团队优先:选择团队熟悉的
- 渐进演进:不要一次性重构
- 测试驱动:架构应该易于测试
- 性能考虑:架构不影响性能
学习建议:
- 从 MVC 开始理解基本概念
- 掌握 MVP 理解分层思想
- 深入学习 MVVM + Repository
- 了解 Clean Architecture 和 MVI
- 根据项目需求选择合适的架构
架构是手段,不是目的。最终目标是写出可维护、可测试、可扩展的代码。