五分钟快速了解MVI、MVVM、MVP

MVI、MVVM、MVP 介绍与区别

在 Android 开发中,MVI、MVVM、MVP 是三种常见的架构模式。它们主要用于 分离 UI 和业务逻辑 ,提高代码的 可维护性 和 可测试性。


1️⃣ MVP(Model-View-Presenter)

📌 介绍

MVP 是一种较早的架构模式,主要将 View 和 Model 解耦,并通过 Presenter 作为中间层。

  • View(界面层):Activity / Fragment,负责 UI 交互。
  • Presenter(业务逻辑层):处理业务逻辑,并通知 View 更新 UI。
  • Model(数据层):负责数据操作,例如数据库、网络请求等。

📌 核心思想 :View 只负责 UI 展示,Presenter 负责逻辑处理,Model 提供数据。


📝 示例

1️⃣ 创建 Model(数据层)
kotlin 复制代码
interface LoginModel {
    fun login(username: String, password: String, callback: (Boolean) -> Unit)
}

class LoginModelImpl : LoginModel {
    override fun login(username: String, password: String, callback: (Boolean) -> Unit) {
        callback(username == "admin" && password == "1234") // 简单模拟
    }
}
2️⃣ 创建 View(UI 层接口)
kotlin 复制代码
interface LoginView {
    fun showLoading()
    fun hideLoading()
    fun showLoginSuccess()
    fun showLoginError()
}
3️⃣ 创建 Presenter(业务逻辑层)
kotlin 复制代码
class LoginPresenter(private val view: LoginView, private val model: LoginModel) {
    fun onLoginClicked(username: String, password: String) {
        view.showLoading()
        model.login(username, password) { isSuccess ->
            view.hideLoading()
            if (isSuccess) view.showLoginSuccess() else view.showLoginError()
        }
    }
}
4️⃣ 在 Activity 中实现 LoginView
kotlin 复制代码
class LoginActivity : AppCompatActivity(), LoginView {
    private lateinit var presenter: LoginPresenter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)
        presenter = LoginPresenter(this, LoginModelImpl())

        findViewById<Button>(R.id.login_button).setOnClickListener {
            presenter.onLoginClicked("admin", "1234")
        }
    }

    override fun showLoading() { /* 显示加载动画 */ }
    override fun hideLoading() { /* 隐藏加载动画 */ }
    override fun showLoginSuccess() { Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show() }
    override fun showLoginError() { Toast.makeText(this, "登录失败", Toast.LENGTH_SHORT).show() }
}

✅ 优势

✔ 解耦 UI 和逻辑 ,View 只负责 UI,Presenter 处理业务逻辑。

✔ Presenter 可单独测试,提高可测试性。

❌ 缺点

❌ Presenter 可能变得很大 ,随着功能增加,可能导致 Presenter 代码臃肿。


2️⃣ MVVM(Model-View-ViewModel)

📌 介绍

MVVM 由 Google 官方推荐,借助 LiveData 或 StateFlow 进行数据绑定,使 ViewModel 持有数据并驱动 UI。

  • Model(数据层):负责数据操作。
  • ViewModel(逻辑层):负责数据处理,使用 LiveData/StateFlow 让 View 观察数据变化。
  • View(界面层):Activity / Fragment,观察 ViewModel 并更新 UI。

📌 核心思想 :View 监听 ViewModel 的数据变化,数据驱动 UI。


📝 示例

1️⃣ 创建 ViewModel
kotlin 复制代码
class LoginViewModel : ViewModel() {
    private val _loginResult = MutableLiveData<Boolean>()
    val loginResult: LiveData<Boolean> get() = _loginResult

    fun login(username: String, password: String) {
        _loginResult.value = (username == "admin" && password == "1234") // 模拟登录
    }
}
2️⃣ 在 Activity 中观察 ViewModel
kotlin 复制代码
class LoginActivity : AppCompatActivity() {
    private lateinit var viewModel: LoginViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)

        viewModel = ViewModelProvider(this)[LoginViewModel::class.java]

        findViewById<Button>(R.id.login_button).setOnClickListener {
            viewModel.login("admin", "1234")
        }

        viewModel.loginResult.observe(this) { isSuccess ->
            if (isSuccess) Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show()
            else Toast.makeText(this, "登录失败", Toast.LENGTH_SHORT).show()
        }
    }
}

✅ 优势

✔ ViewModel 生命周期安全 ,不会因 Activity 旋转而丢失数据。

✔ View 只监听数据变化,减少 UI 层代码 。

✔ 数据驱动 UI,逻辑更清晰。

❌ 缺点

❌ LiveData 可能导致内存泄漏 (如果没有正确清理)。

❌ 数据流动较隐式,初学者可能不容易理解。


3️⃣ MVI(Model-View-Intent)

📌 介绍

MVI 采用 单向数据流 ,View 触发 Intent(用户意图),ViewModel 处理后更新 State(状态),然后 View 监听 State 变化。

  • Model(数据层):提供数据。
  • View(界面层):监听 State 并更新 UI。
  • Intent(用户意图):用户的操作,如点击按钮。
  • State(状态):ViewModel 维护的 UI 状态,View 观察它。

📌 核心思想 :UI 由 State 驱动,所有事件是单向的,确保数据一致性。


📝 示例

1️⃣ 定义 UI 状态
kotlin 复制代码
data class LoginState(val isLoading: Boolean = false, val isSuccess: Boolean? = null)
2️⃣ 创建 ViewModel
kotlin 复制代码
class LoginViewModel : ViewModel() {
    private val _state = MutableStateFlow(LoginState())
    val state: StateFlow<LoginState> get() = _state

    fun login(username: String, password: String) {
        _state.value = LoginState(isLoading = true)
        viewModelScope.launch {
            delay(1000) // 模拟网络请求
            _state.value = LoginState(isSuccess = (username == "admin" && password == "1234"))
        }
    }
}
3️⃣ 在 Activity 中监听状态
kotlin 复制代码
class LoginActivity : AppCompatActivity() {
    private lateinit var viewModel: LoginViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)

        viewModel = ViewModelProvider(this)[LoginViewModel::class.java]

        lifecycleScope.launch {
            viewModel.state.collect { state ->
                if (state.isLoading) showLoading()
                else if (state.isSuccess == true) showSuccess()
                else showError()
            }
        }
    }
}

✅ 优势

✔ 状态管理清晰 ,避免数据不一致。

✔ 单向数据流,逻辑更易维护。

❌ 缺点

❌ 需要理解 StateFlow / Redux 思想,初学者不易上手。


🔥 总结

架构 适用场景 优势 缺点
MVP 小型项目 解耦 UI 和逻辑 Presenter 可能变大
MVVM 官方推荐 数据驱动 UI 可能导致内存泄漏
MVI 状态驱动 单向数据流,数据一致性好 学习曲线较陡

如果是 现代 Android 开发,推荐 MVVM / MVI 🚀。

相关推荐
大圣编蚕6 小时前
初探 NDK 的世界:从零开始理解 Android 原生开发
android
云贝贝贝6 小时前
MySQL 慢查询定位与索引优化实战
android
骑着蜗牛撵大象3277 小时前
服务下线不再炸:分层关闭、TCP 存活探测与负载均衡排水的落地套路
android·tcp/ip·负载均衡·tcp·高可用·健康检查·优雅关闭
三少爷的鞋9 小时前
别再这么写协程了!Marcin Moskała 剖析的 几个常见协程误区与重构
android
mmsx11 小时前
Android 防二次打包第一道锁:签名校验与完整性校验
android·kotlin
mmsx11 小时前
Android 混淆不等于安全:二次打包链路完整走一遍
android·kotlin
小宋102112 小时前
Agent轨迹级评测实战:工具选择、预算超限与回归门禁
android·网络·人工智能·回归
墨天梦14 小时前
D05_ViewModel与单向数据流
android·kotlin
蒸鱼Yuzheng16 小时前
Android 构建可复现性:APK 指纹、文件级差异与供应链审计
android·apk·devops·软件供应链·可复现构建
墨天梦18 小时前
D03_Compose列表与稳定身份
android·gitee·kotlin