一、为什么需要架构?
- 业务膨胀:Activity/Fragment 中混杂 UI、数据、网络、缓存,导致数千行“上帝类”。
- 维度冲突:UI 与状态同步困难,生命周期横插一刀,配置更改即崩溃。
- 测试困难:逻辑耦合在 Android 生命周期中,单元测试寸步难行。
架构模式通过关注点分离(SoC)与单向数据流(UDF)缓解上述痛点。
二、四种主流架构速览
| 维度 | MVC(Model-View-Controller) | MVP(Model-View-Presenter) | MVVM(Model-View-ViewModel) | MVI(Model-View-Intent) |
|---|---|---|---|---|
| 数据流方向 | 双向 | 双向 | 双向(基于观察者) | 严格单向环形 |
| 生命周期感知 | 无 | 手动 detach | ViewModel 自动感知 | StateFlow/Compose 自动感知 |
| 样板代码 | 极少 | 中等(接口爆炸) | 中等(DataBinding/ViewBinding) | 最少(Kotlin DSL) |
| 状态管理 | 分散 | Presenter 持有 | LiveData/StateFlow 集中 | 单一不可变 State |
| 适用场景 | 原型/小 Demo | 传统业务模块 | Jetpack 全家桶 | Compose/响应式新 UI |
三、MVC:最原始的双向绑定
3.1 角色划分
- Model:业务数据与持久化。
- View:XML + Activity 展示。
- Controller:Activity 自身,响应 View 事件并更新 Model,同时监听 Model 变化刷新 View。
3.2 代码示例
// Model
object UserModel {
fun fetchUser(callback: (User) -> Unit) {
// 模拟网络
Handler(Looper.getMainLooper()).postDelayed({
callback(User("MVC User"))
}, 1000)
}
}
// Controller = Activity
class UserActivity : AppCompatActivity() {
private val model = UserModel
private lateinit var textView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user)
textView = findViewById(R.id.tvName)
model.fetchUser {
user ->
textView.text = user.name // Controller 直接改 View
}
}
}
问题:Activity 既是 Controller 又是 View,配置更改后需手动保存数据,极易内存泄漏。
四、MVP:接口解耦,职责清晰
4.1 角色划分
- View:Activity/Fragment,通过接口抽象 UI 操作。
- Presenter:纯 Java/Kotlin 类,持有 View 接口引用,调度 Model。
- Model:与 MVC 相同。
4.2 关键改进
- 面向接口编程,单元测试可 mock View。
- 手动
attach/detach避免内存泄漏。
4.3 代码示例(登录场景)
// Contract
interface LoginContract {
interface View {
fun showLoading()
fun hideLoading()
fun showError(msg: String)
fun navigateHome(user: User)
}
interface Presenter {
fun attachView(view: View)
fun detachView()
fun login(user: String, pwd: String)
}
}
// Presenter
class LoginPresenter

1277

被折叠的 条评论
为什么被折叠?



