Android 架构模式的演变(MVC、MVP、MVVM、MVI)

目录

一、为什么要使用架构

二、传统起点:MVC模式

[2.1 MVC的基本概念](#2.1 MVC的基本概念)

[2.2 Android中的MVC实现](#2.2 Android中的MVC实现)

[2.3 MVC的优势与问题](#2.3 MVC的优势与问题)

三、改进之路:MVP模式

[3.1 MVP的核心思想(解耦的极致追求)](#3.1 MVP的核心思想(解耦的极致追求))

[3.2 MVP的关键特征](#3.2 MVP的关键特征)

[3.3 MVP的实现示例](#3.3 MVP的实现示例)

[3.3.1 UserContract.java](#3.3.1 UserContract.java)

[3.3.2 UserPresenter.java (Presenter层)](#3.3.2 UserPresenter.java (Presenter层))

[3.3.3 UserActivity.java (View层)](#3.3.3 UserActivity.java (View层))

[3.3.4 UserModel.java (Model层)](#3.3.4 UserModel.java (Model层))

[3.4 MVP的优势与挑战](#3.4 MVP的优势与挑战)

四、现代选择:MVVM模式

[4.1 MVVM的设计理念](#4.1 MVVM的设计理念)

[4.2 MVVM的关键技术](#4.2 MVVM的关键技术)

[4.3 MVVM的实现示例](#4.3 MVVM的实现示例)

[4.3.1 UserViewModel.kt (ViewModel层)](#4.3.1 UserViewModel.kt (ViewModel层))

[4.3.2 UserActivity.kt (View层)](#4.3.2 UserActivity.kt (View层))

[4.3.3 activity_user.xml](#4.3.3 activity_user.xml)

[4.4 MVVM的优势与考量](#4.4 MVVM的优势与考量)

[五、MVI ------ 2025 年的架构新范式](#五、MVI —— 2025 年的架构新范式)

[4.1 MVI核心理念:单向数据流](#4.1 MVI核心理念:单向数据流)

[4.2 MVI核心组件详解](#4.2 MVI核心组件详解)

[4.2.1 Model - 应用状态](#4.2.1 Model - 应用状态)

[4.2.2 View - 状态渲染器](#4.2.2 View - 状态渲染器)

[4.2.3 Intent - 用户意图](#4.2.3 Intent - 用户意图)

[4.2.4 ViewModel - Reducer概念](#4.2.4 ViewModel - Reducer概念)

六、总结:架构演进的本质是"状态管理"的进化


在Android开发的世界里,架构模式的选择直接影响着应用的可维护性、可测试性和可扩展性。随着Android平台的不断演进,架构模式也从早期的MVC发展到MVP再到如今的MVVM,并涌现出像MVI这样的新思路。本文将深入探讨Android架构模式的演变历程,分析每种模式的特点、优势与局限。

一、为什么要使用架构

在架构意识尚未觉醒的年代,一个典型的 MainActivity 往往集万千职责于一身

  • 通过 findViewById 操作 UI 控件;

  • 直接发起 OkHttp 网络请求;

  • 使用 Room 或 SQLiteOpenHelper 操作数据库;

  • onCreate() 中处理业务逻辑分支;

  • onActivityResult() 中解析 Intent 数据;

  • 甚至内嵌 AsyncTask 处理异步任务......

这种"上帝类"模式看似高效,实则埋下巨大隐患:

问题维度 具体表现
高耦合 UI、网络、DB、业务逻辑全部交织,修改一处可能引发连锁崩溃
不可测试 业务逻辑强依赖 ContextActivity 等 Android SDK 类型,无法脱离设备运行单元测试
状态脆弱 屏幕旋转导致 Activity 重建,未妥善保存的数据(如网络加载中的状态)瞬间丢失
维护地狱 单文件超 2000 行代码,新人接手需数周才能理清逻辑

正是这种"开发快、维护慢、测试难"的恶性循环,催生了对架构模式的迫切需求。而第一个被引入的,便是软件工程的经典范式------MVC

二、传统起点:MVC模式

2.1 MVC的基本概念

MVC(Model-View-Controller)是最早被引入Android开发的架构模式,它将应用程序分为三个核心组件:

  • Model:负责数据和业务逻辑,与数据库、网络等数据源交互

  • View用户界面,负责数据的可视化展示, Acitivity(View)、Fragment(View)视图,在android里xml布局转成View后,加载到了Activity/Fragment里了。

  • Controller :**协调Model和View之间的交互,**Controller对应着Activity/Fragment,绑定UI,处理各种业务。

2.2 Android中的MVC实现

在传统的Android MVC实现中:

  • Model:数据类、数据库操作类、网络请求类

  • View:XML布局文件

  • Controller:Activity和Fragment

java 复制代码
// 传统MVC示例
public class UserActivity extends AppCompatActivity {
    // Controller部分
    private TextView nameTextView; // View部分
    private UserModel userModel;   // Model部分
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user);
        
        nameTextView = findViewById(R.id.name_text_view);
        userModel = new UserModel();
        
        loadUserData();
    }
    
    private void loadUserData() {
        User user = userModel.getUser(); // 从Model获取数据
        nameTextView.setText(user.getName()); // 更新View
    }
}

2.3 MVC的优势与问题

优势:

  • 结构简单,容易理解

  • 职责分离,有一定程度的模块化

问题:

  • Activity/Fragment负担过重:既承担Controller职责,又处理View逻辑

  • 测试困难:业务逻辑与Android组件紧密耦合

  • 代码臃肿:随着功能增加,Activity可能变得非常庞大

三、改进之路:MVP模式

3.1 MVP的核心思想(解耦的极致追求)

MVP(Model-View-Presenter)模式针对MVC的问题进行了改进,引入了Presenter层:

  • Model:与MVC相同,负责数据和业务逻辑

  • View:界面显示,通过接口定义与Presenter的契约

  • Presenter:中间人,处理业务逻辑,协调Model和View

3.2 MVP的关键特征

  1. View通过接口抽象:减少对Android框架的依赖

  2. Presenter持有View弱引用:避免内存泄漏

  3. 单向数据流:View → Presenter → Model → Presenter → View

3.3 MVP的实现示例

3.3.1 UserContract.java

java 复制代码
//抽象接口
public interface UserContract {
    interface View {
        void showUserName(String name);
        void showError(String message);
    }
    
    interface Presenter {
        void loadUser();
        void onDestroy();
    }
}

作用:明确定义View和Presenter之间的通信协议

  • View接口定义UI能做什么(显示数据、显示错误)

  • Presenter接口定义业务逻辑能做什么(加载用户、清理资源)

3.3.2 UserPresenter.java (Presenter层)

java 复制代码
// Presenter实现
public class UserPresenter implements UserContract.Presenter {
    private UserContract.View view;
    private UserModel model;
    
    public UserPresenter(UserContract.View view) {
        this.view = view;
        this.model = new UserModel();
    }
    
    @Override
    public void loadUser() {
        model.getUser(new Callback<User>() {
            @Override
            public void onSuccess(User user) {
                if (view != null) {
                    view.showUserName(user.getName());
                }
            }
            
            @Override
            public void onError(String message) {
                if (view != null) {
                    view.showError(message);
                }
            }
        });
    }
    
    @Override
    public void onDestroy() {
        view = null; // 避免内存泄漏
    }
}

核心职责

  • 作为 View和Model的中介

  • 处理业务逻辑

  • 从Model获取数据,处理后通知View更新

将两者彻底分开,互不干扰,将职责分离

3.3.3 UserActivity.java (View层)

java 复制代码
// Activity作为View实现
public class UserActivity extends AppCompatActivity implements UserContract.View {
    private UserPresenter presenter;
    private TextView nameTextView;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user);
        
        nameTextView = findViewById(R.id.name_text_view);
        presenter = new UserPresenter(this);
        presenter.loadUser();
        //也可以是点击触发
    
    }
    
    @Override
    public void showUserName(String name) {
        nameTextView.setText(name);
    }
    
    @Override
    public void showError(String message) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        presenter.onDestroy();
    }
}

核心职责

  • 只负责 UI显示和用户交互

  • 实现View接口,成为Presenter的"客户端"

  • 将业务逻辑委托给Presenter处理

3.3.4 UserModel.java (Model层)

java 复制代码
// 假设的Model类
public class UserModel {
    public void getUser(Callback<User> callback) {
        // 模拟网络请求或数据库查询
        new Handler().postDelayed(() -> {
            callback.onSuccess(new User("张三"));
        }, 1000);
    }
}

核心职责

  • 数据获取(网络、数据库、文件等)

  • 数据处理和存储

3.4 MVP的优势与挑战

优势:

  • 更好的解耦:View通过接口与Presenter交互

  • 便于单元测试:业务逻辑在Presenter中,可以独立测试

  • 职责清晰:Presenter专注于业务逻辑,View专注于界面

挑战:

  • 接口爆炸每个View都需要定义接口

  • Presenter可能变得臃肿:复杂页面的Presenter可能包含大量逻辑

  • 生命周期管理复杂:需要手动处理View的绑定和解绑

四、现代选择:MVVM模式

4.1 MVVM的设计理念

MVVM (Model-View-ViewModel)由微软提出,**在Android中结合Data Binding和LiveData等技术大放异彩,**这个后面的文章会着重介绍

  • Model:与MVP相同,负责数据和业务逻辑

  • View:用户界面,观察ViewModel的数据变化

  • ViewModel:持有UI相关的数据,提供View需要的数据和命令

4.2 MVVM的关键技术

  1. 数据绑定:自动同步View和ViewModel的数据

  2. 观察者模式:View观察ViewModel的数据变化

  3. 生命周期感知:LiveData/Flow自动处理生命周期

4.3 MVVM的实现示例

4.3.1 UserViewModel.kt (ViewModel层)

Kotlin 复制代码
// ViewModel
class UserViewModel : ViewModel() {
    // 持有 Model 层引用
    private val repository = UserRepository()
    
    // LiveData观察用户数据
    private val _user = MutableLiveData<User>()
    val user: LiveData<User> = _user
    
    private val _error = MutableLiveData<String>()
    val error: LiveData<String> = _error
    
    // 业务逻辑方法
    fun loadUser() {
        // viewModelScope 自动管理协程生命周期
        viewModelScope.launch {
            try {
                // 调用 Model 层获取数据
                val user = repository.getUser()
                _user.value = user
            } catch (e: Exception) {
                _error.value = "加载失败: ${e.message}"
            }
        }
    }
}

ViewModel 关键点

  1. 继承 ViewModel:生命周期比 Activity/Fragment 长

  2. LiveData :实现观察者模式,数据变化时通知观察者

  3. 线程管理:后台操作避免阻塞 UI 线程

  4. 状态管理:管理加载、错误、成功等状态

4.3.2 UserActivity.kt (View层)

Kotlin 复制代码
// Activity/Fragment作为View
class UserActivity : AppCompatActivity() {
    private lateinit var binding: ActivityUserBinding
    private val viewModel: UserViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // Data Binding初始化
        binding = DataBindingUtil.setContentView(this, R.layout.activity_user)
        binding.lifecycleOwner = this
        
        // 观察LiveData
        viewModel.user.observe(this) { user ->
            binding.user = user
        }
        
        viewModel.error.observe(this) { error ->
            Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
        }
        
        // 加载数据
        viewModel.loadUser()
    }
}

4.3.3 activity_user.xml

XML 复制代码
<!-- Data Binding布局示例 -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable 
            name="user" 
            type="com.example.User" />
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}" />
            
    </LinearLayout>
</layout>

其实抛开Data Binding 不谈 也是标准的MVVM结构,这里只是锦上添花下。主要的是理解 ViewModel就可以了。

4.4 MVVM的优势与考量

优势:

  • 双向数据绑定:减少模板代码

  • 响应式编程:数据变化自动更新UI

  • 更好的生命周期管理:LiveData自动处理

  • UI与业务逻辑彻底分离

考量:

  • 调试困难:数据绑定错误可能难以追踪

  • 学习曲线:需要理解响应式编程概念

  • 过度使用数据绑定:可能导致性能问题

五、MVI ------ 2025 年的架构新范式

MVVM 并非终点。随着应用复杂度提升与声明式 UI 的普及,新一代架构思想正在融合演进:

4.1 MVI核心理念:单向数据流

MVI(Model-View-Intent)是一种响应式架构模式,强调单向数据流不可变状态

4.2 MVI核心组件详解

4.2.1 Model - 应用状态

在MVI中,Model不是数据类,而是整个应用的状态

Kotlin 复制代码
// 1. 定义状态(Model) - 整个App的状态
data class CounterState(
    val count: Int = 0,          // 当前计数
    val isLoading: Boolean = false, // 是否正在加载
    val error: String? = null      // 错误信息
)

4.2.2 View - 状态渲染器

View只做一件事:根据当前状态渲染界面

Kotlin 复制代码
// 2. Activity(View) - 渲染状态并发送Intent
class CounterActivity : AppCompatActivity() {
    
    private lateinit var viewModel: CounterViewModel
    private lateinit var countText: TextView
    private lateinit var loadingIndicator: ProgressBar
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_counter)
        
        // 初始化ViewModel
        viewModel = ViewModelProvider(this)[CounterViewModel::class.java]
        
        // 绑定View
        countText = findViewById(R.id.count_text)
        loadingIndicator = findViewById(R.id.loading_indicator)
        
        val incrementBtn: Button = findViewById(R.id.increment_btn)
        val decrementBtn: Button = findViewById(R.id.decrement_btn)
        val resetBtn: Button = findViewById(R.id.reset_btn)
        val loadBtn: Button = findViewById(R.id.load_btn)
        
        // 5. 观察状态变化并渲染
        viewModel.state.onEach { state ->
            render(state)
        }.launchIn(lifecycleScope)
        
        // 6. 设置点击监听,发送Intent
        incrementBtn.setOnClickListener {
            viewModel.processIntent(CounterIntent.IncrementIntent)
        }
        
        decrementBtn.setOnClickListener {
            viewModel.processIntent(CounterIntent.DecrementIntent)
        }
        
        resetBtn.setOnClickListener {
            viewModel.processIntent(CounterIntent.ResetIntent)
        }
        
        loadBtn.setOnClickListener {
            viewModel.processIntent(CounterIntent.LoadCountIntent)
        }
    }
    
    // 7. 渲染函数:根据状态更新UI
    private fun render(state: CounterState) {
        // 更新计数显示
        countText.text = "当前计数: ${state.count}"
        
        // 控制加载指示器
        loadingIndicator.visibility = if (state.isLoading) View.VISIBLE else View.GONE
        
        // 显示错误信息
        state.error?.let { error ->
            Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
        }
    }
}

4.2.3 Intent - 用户意图

Intent不是Android的Intent,而是用户意图的抽象

java 复制代码
// 3. 定义意图(Intent) - 用户可能的操作
sealed class CounterIntent {
    object IncrementIntent : CounterIntent()    // 点击增加按钮
    object DecrementIntent : CounterIntent()    // 点击减少按钮
    object ResetIntent : CounterIntent()        // 点击重置按钮
    object LoadCountIntent : CounterIntent()    // 加载保存的计数
}

4.2.4 ViewModel - Reducer概念

Reducer是纯函数,接收当前状态和Intent,返回新状态。

Kotlin 复制代码
当前状态 + Intent → Reducer → 新状态
Kotlin 复制代码
// 3. ViewModel - 处理Intent并管理状态
class CounterViewModel : ViewModel() {
    
    // 当前状态
    private val _state = MutableStateFlow(CounterState())
    val state: StateFlow<CounterState> = _state
    
    // 处理用户意图
    fun processIntent(intent: CounterIntent) {
        // 根据不同的Intent,生成新的状态
        val newState = when (intent) {
            is CounterIntent.IncrementIntent -> {
                // 当前计数 + 1
                _state.value.copy(
                    count = _state.value.count + 1,
                    error = null
                )
            }
            
            is CounterIntent.DecrementIntent -> {
                // 当前计数 - 1(但不小于0)
                val newCount = if (_state.value.count > 0) {
                    _state.value.count - 1
                } else {
                    0
                }
                _state.value.copy(
                    count = newCount,
                    error = null
                )
            }
            
            is CounterIntent.ResetIntent -> {
                // 重置为0
                _state.value.copy(
                    count = 0,
                    error = null
                )
            }
            
            is CounterIntent.LoadCountIntent -> {
                // 模拟加载数据
                _state.value.copy(isLoading = true)
                
                // 模拟网络请求(2秒后完成)
                viewModelScope.launch {
                    delay(2000) // 模拟网络延迟
                    
                    // 模拟加载到的数据
                    val savedCount = 5
                    
                    _state.value = _state.value.copy(
                        count = savedCount,
                        isLoading = false,
                        error = null
                    )
                }
                
                // 立即返回加载中的状态
                _state.value.copy(isLoading = true)
            }
        }
        
        _state.value = newState
    }
}

通过这个简单例子,可以看到MVI的三个核心:

  1. Model就是状态

    • 不是数据类,是整个UI的状态

    • 包含所有UI需要的信息

  2. Intent是用户意图

    • 不是Android的Intent

    • 是用户操作的抽象表示

  3. View只做两件事

    • 发送Intent(用户操作)

    • 根据状态渲染UI

六、总结:架构演进的本质是"状态管理"的进化

维度 MVC MVP MVVM MVI(2025)
状态持有者 Activity Presenter ViewModel StateFlow
UI 更新方式 手动调用 回调接口 观察数据 响应状态
生命周期管理 手动 手动(易错) 自动 自动
可测试性 极好 极好
核心哲学 分离职责 彻底解耦 数据驱动 单向数据流
相关推荐
与水同流1 天前
GNSS数据格式
android
狗哥哥1 天前
企业级 Vue3 + Element Plus 主题定制架构:从“能用”到“好用”的进阶之路
前端·css·架构
梦想画家1 天前
Rust模块化开发从入门到精通:用mod搭建高可维护项目架构
架构·rust·模块化开发
缘友一世1 天前
区块链原理与体系架构
架构·区块链
切糕师学AI1 天前
MIPS架构是什么?
架构·处理器架构
Mars-xq1 天前
Android godot 交互数据监听
android·godot·交互
_李小白1 天前
【Android FrameWork】延伸阅读: PowerManagerService
android
无忧智库1 天前
深度解读|某县域“十五五”数字农业示范区与高标准农田物联网建设方案(附技术架构、风险防控与实施路径)
物联网·架构