移动应用架构设计:MVVM实战教程(零基础友好)
一、开篇:什么是MVVM?它用来做什么?

在移动开发中,我们常常会遇到一个问题:“代码写得很乱,后期很难维护。”
为了避免这种情况,开发者们总结出了一套结构清晰、易于扩展的开发方式,叫做 架构设计模式。今天我们要学习的 MVVM(Model-View-ViewModel),就是目前最流行的一种架构模式。
简单理解 MVVM 的三个部分:
| 层级 | 中文名 | 作用 |
|---|---|---|
| Model | 数据层 | 处理数据相关逻辑(比如从服务器取数据) |
| View | 视图层 | 用户看得到的部分(比如按钮、文字) |
| ViewModel | 视图模型 | 连接数据和视图,处理业务逻辑 |
💡 为什么用 MVVM?
- 清晰分离关注点(各司其职)
- 更容易测试代码
- 后期维护成本低
二、环境准备:搭建你的开发环境


⚠️ 假设你已经安装了 Android Studio。如果没有,请先去官网下载并安装。
步骤 1:创建一个新项目
- 打开 Android Studio
- 点击
New Project - 选择模板:Empty Activity
- 项目名称:
MVVMExample - 语言选择:✅ Kotlin(更推荐)、Java 也可以
- 完成创建
步骤 2:添加 Jetpack 库支持(Google 官方推荐)
打开 build.gradle (Module: app) 文件,在 dependencies{} 中加入以下依赖:
// Lifecycle & ViewModel 支持
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.1'
// Room 数据库支持(可选)
implementation "androidx.room:room-runtime:2.5.2"
kapt "androidx.room:room-compiler:2.5.2"
// Retrofit 网络请求(可选)
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
然后点击 Sync Now 同步构建。
📌 新手小贴士:
- 如果遇到同步失败,检查网络连接或尝试使用科学上网工具。
- 初学时可以先不加 Room 和 Retrofit,后面再逐步加入。
三、核心概念讲解(结合代码示例)
我们通过一个简单的 App 来理解 MVVM,App 功能是显示一段文本:“Hello, MVVM!”。
3.1 Model 层(数据层)
我们模拟一个数据源,返回字符串内容。
步骤:
- 新建包:
model - 创建类
TextRepository.kt
class TextRepository {
fun getWelcomeText(): String {
return "Hello, MVVM!"
}
}
📌 解释:
Repository是数据来源的封装,它可以来自网络、数据库、本地等。- 这里为了简单起见,直接返回一个静态字符串。
3.2 ViewModel 层(视图模型)
ViewModel 担任 View 和 Model 之间的桥梁。
步骤:
- 新建包:
viewmodel - 添加类
MainViewModel.kt
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
class MainViewModel : ViewModel() {
private val repository = TextRepository()
// 使用 liveData 分发数据给视图
val welcomeText = repository.getWelcomeText()
}
📌 解释:
ViewModel类继承自ViewModel,生命周期与页面绑定。viewModelScope是协程作用域,方便做异步操作(例如联网请求)。
3.3 View 层(用户界面)
View 就是我们看到的界面 UI。在 Android 中通常是一个 Activity 或 Fragment。
步骤:
修改 activity_main.xml 文件:
<TextView
android:id="@+id/tv_welcome"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:layout_centerInParent="true"/>
接下来修改 MainActivity.kt 文件:
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 获取 TextView 控件
val textView = findViewById<TextView>(R.id.tv_welcome)
// 初始化 ViewModel
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
// 显示数据
textView.text = viewModel.welcomeText
}
}
📌 解释:
ViewModelProvider用于获取或创建 ViewModel 实例。- 这样即使屏幕旋转,数据也不会丢失。
四、实战项目:做一个“随机笑话生成器”
我们来做一个更有意思的小项目 —— 随机笑话生成器!每次点击按钮就换一个新的笑话。
4.1 需求分析
- 显示一句话笑话
- 有个按钮“换一个”
- 笑话由 ViewModel 提供
- 笑话存储在 Repository 中
4.2 修改 Model(增加笑话数据)
新建 JokeRepository.kt
class JokeRepository {
private val jokes = listOf(
"程序员最爱的一首歌:Ctrl+C Ctrl+V",
"我跟老板说我想休假……他说‘好啊,那工资自动清零’。",
"程序员不会死,只是内存泄漏了。",
"今天去面试Android工程师,结果让我讲个笑话…我说了一个叫MVVM。",
"没有 Bug 的代码,就像没有空气的地球——根本活不了!"
)
fun getRandomJoke(): String {
return jokes.random()
}
}
4.3 修改 ViewModel(新增方法)
修改 MainViewModel.kt
class MainViewModel : ViewModel() {
private val repository = JokeRepository()
fun getRandomJoke(): String {
return repository.getRandomJoke()
}
}
4.4 修改布局文件(activity_main.xml)
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="@+id/tv_joke"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:padding="16dp"
android:text="这里显示笑话"/>
<Button
android:id="@+id/btn_new_joke"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="换一个"/>
</LinearLayout>
4.5 修改 MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
private lateinit var tvJoke: TextView
private lateinit var btnNewJoke: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tvJoke = findViewById(R.id.tv_joke)
btnNewJoke = findViewById(R.id.btn_new_joke)
viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
// 初始加载一个笑话
tvJoke.text = viewModel.getRandomJoke()
// 按钮点击事件
btnNewJoke.setOnClickListener {
tvJoke.text = viewModel.getRandomJoke()
}
}
}
✨ 运行一下看看效果吧!
五、常见问题解答(FAQ)

❓ Q1:MVVM 和 MVP 是什么关系?哪个更好?
- MVP(Model-View-Presenter) 是早期流行的结构模式,Presenter 与 View 强关联。
- MVVM 更适合数据驱动的场景,尤其是配合 LiveData/StateFlow 使用非常灵活。
- 对初学者来说,MVVM + Jetpack 架构组件 是目前 Android 主流做法,建议优先掌握。
❓ Q2:ViewModel 只能在 Activity 中使用吗?能不能在 Fragment 中用?
- 当然可以在 Fragment 中使用。
- 调用方式一样:
val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
区别在于传入的上下文(this)。Fragment 中 this 指的是 Fragment 自己。
❓ Q3:LiveData 是什么?一定要用吗?
- LiveData 是一种可观察的数据持有者,它能感知生命周期。
- 当前页面不可见(比如后台)时,不会更新 UI,防止内存泄漏。
- 初学阶段可以直接暴露为普通变量,但建议尽早熟悉 LiveData。
❓ Q4:如何测试 ViewModel 中的逻辑?
- 可以使用
JUnit单元测试 ViewModel。 - 举例:
@Test
fun testRandomJokeNotEmpty() {
val viewModel = MainViewModel()
val joke = viewModel.getRandomJoke()
assertTrue(joke.isNotEmpty())
}
📌 推荐在 Gradle 配置中加入 testImplementation 'junit:junit:4.13.2'
六、下一步学习建议
恭喜你完成了第一个基于 MVVM 架构的 App!
接下来你可以继续深入学习以下几个方向:
🧩 1. 加入网络请求(Retrofit + Coroutines)
- 学习使用
Retrofit请求 API - 结合
ViewModel与LiveData显示远程数据
🧩 2. 使用 Room 数据库持久化
- 学习本地数据库保存数据
- 如笑话收藏功能
🧩 3. 引入 Navigation 组件简化页面跳转
- 使用 Jetpack Navigation 管理页面导航
- 有助于构建复杂 App
🧩 4. 理解 Clean Architecture 分层思想
- 分清不同层级的责任边界
- 项目结构更规范,利于长期维护
🧩 5. 学习 Compose + MVVM 结合
- Android 最新的 UI 框架 Jetpack Compose
- 与 MVVM 配合也非常棒
总结
本文带你从零开始认识并实践了 MVVM 架构,通过一个“随机笑话生成器”项目的完整实现,了解了 MVVM 的三大组成部分:
- Model(数据层)
- ViewModel(数据与 UI 交互中心)
- View(UI 层)
希望你能动手跟着写一遍,边学边练才记得牢。
如果你愿意继续深入学习,欢迎查看我们的下一讲《高级 MVVM 技术:搭配 Retrofit 与 LiveData》。
Happy coding! 🚀
作者简介:一位深耕 Android 教育多年的讲师,专注帮助编程小白快速入门,擅长将复杂知识拆解为通俗易懂的例子。欢迎关注我的博客与课程系列,一起成为更好的开发者!

评论 0