移动应用架构设计:MVVM实战(零基础也能懂)

线程池保洁员
2025-12-13 13:36
阅读 223

作者:一个从中文系转行做移动开发的“老”程序员。当初学 MVVM 的时候,被一堆英文缩写绕得头晕眼花。今天,我就用最接地气的方式,带你从零开始搞懂它。


为什么我要写这篇教程?

我当初自学 Android 开发时,一上来就写 Activity 里塞满逻辑、网络请求、UI 更新……结果代码像一锅乱炖,改一处崩三处。后来接触到 MVVM 架构,才真正理解什么叫“代码有组织、开发不抓狂”。

更巧的是,现在很多公司(尤其是涉及运营后台 + App 联动的场景)都采用 SpringBoot 做后端服务,前端用 MVVM 写 App。所以,这篇教程不仅教你 MVVM,还会让你看到它和 SpringBoot 如何配合——哪怕你是文科生,也能看懂!


一、MVVM 是什么?能干啥?

MVVM = Model + View + ViewModel

你可以把它想象成一家奶茶店:

  • Model:原料库(数据来源,比如用户信息、商品列表)
  • View:前台点单界面(你看到的 App 页面)
  • ViewModel:店员(负责把原料变成奶茶,并告诉前台“做好了!”)

核心思想:让 UI(View)只管“显示”,不管“怎么拿数据”。数据变了,自动刷新界面——这就是 数据驱动 UI

✅ 优点:代码清晰、易测试、不怕产品经理临时改需求!


二、环境准备(5 分钟搞定)

我们要做一个超简单的 App:从 SpringBoot 后台获取一条“今日运营公告”,显示在手机上。

所需工具

工具 版本建议 用途
Android Studio Giraffe 或以上 写 App
JDK 17 运行 Java/Kotlin
IntelliJ IDEA (或复用 AS) 最新版 写 SpringBoot 后端
Postman(可选) - 测试接口

步骤

  1. 安装 Android Studio:官网下载安装即可。
  2. 创建 Android 项目
    • 语言选 Kotlin
    • Minimum SDK 选 API 21 (Android 5.0)(兼容性好)
  3. 添加必要依赖(在 app/build.gradle 中):
dependencies {
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.2")
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    implementation("com.squareup.retrofit2:converter-gson:2.9.0")
}

💡 我当初漏加 livedata 依赖,ViewModel 数据变了 UI 却不更新,折腾半天才发现!


三、核心概念通俗讲

1. ViewModel:UI 的“私人助理”

  • 不会随屏幕旋转销毁(Activity 会!)
  • 它持有 LiveData(一种“可观察的数据”)

2. LiveData:会“喊话”的数据

  • 当数据更新,所有“监听者”(比如 TextView)自动收到通知
  • 自动处理生命周期(App 退到后台就不会回调,防内存泄漏)

3. Model:数据从哪来?

  • 可以是本地数据库、网络接口(我们这里用 SpringBoot 提供的 API)

四、实战:做一个“运营公告”App

第一步:写 SpringBoot 后端(3 行代码!)

创建一个 SpringBoot 项目(用 start.spring.io 快速生成),添加一个 Controller:

// AnnouncementController.java
@RestController
public class AnnouncementController {

    @GetMapping("/api/announcement")
    public Map<String, String> getAnnouncement() {
        Map<String, String> resp = new HashMap<>();
        resp.put("content", "【运营通知】今日全场奶茶第二杯半价!");
        return resp;
    }
}

启动后,访问 http://localhost:8080/api/announcement,你会看到:

{"content":"【运营通知】今日全场奶茶第二杯半价!"}

🎯 这就是我们 App 要显示的内容!


第二步:定义数据模型(Model)

在 Android 项目中创建 Announcement.kt

data class Announcement(
    val content: String
)

第三步:写网络请求(Retrofit)

创建 ApiService.kt

interface ApiService {
    @GET("api/announcement")
    suspend fun getAnnouncement(): Announcement
}

// 工具类
object ApiClient {
    private const val BASE_URL = "http://10.0.2.2:8080/" // Android 模拟器访问本机

    val instance: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}

⚠️ 注意:10.0.2.2 是 Android 模拟器访问电脑 localhost 的特殊 IP!真机调试要用电脑 IP。


第四步:写 ViewModel

class AnnouncementViewModel : ViewModel() {
    private val _announcement = MutableLiveData<Announcement>()
    val announcement: LiveData<Announcement> = _announcement

    fun fetchAnnouncement() {
        viewModelScope.launch {
            try {
                val data = ApiClient.instance.getAnnouncement()
                _announcement.value = data
            } catch (e: Exception) {
                // 实际项目要处理错误,这里简化
            }
        }
    }
}

🔍 viewModelScope.launch:在 ViewModel 中安全地启动协程(Kotlin 异步神器)


第五步:写 UI(View)

修改 MainActivity.kt

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var viewModel: AnnouncementViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

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

        // 观察数据变化
        viewModel.announcement.observe(this) { announcement ->
            binding.textView.text = announcement.content
        }

        // 点击按钮刷新
        binding.button.setOnClickListener {
            viewModel.fetchAnnouncement()
        }

        // 首次加载
        viewModel.fetchAnnouncement()
    }
}

对应的 activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="加载中..." />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="刷新公告" />

</LinearLayout>

第六步:别忘了网络权限!

AndroidManifest.xml 中添加:

<uses-permission android:name="android.permission.INTERNET" />

五、常见问题 & 避坑指南

问题 原因 解决方案
点击按钮没反应 忘记调用 fetchAnnouncement() 检查按钮点击监听是否绑定
显示“加载中...”不动 网络请求失败 1. 检查 SpringBoot 是否运行
2. 模拟器用 10.0.2.2,真机用电脑 IP
3. 关闭电脑防火墙
屏幕旋转后数据消失 把数据存在 Activity 里了 一定要用 ViewModel + LiveData
编译报错 Unresolved reference: binding 忘记启用 ViewBinding build.gradle 中添加:
buildFeatures { viewBinding true }

💡 我当初在咖啡馆用公共 Wi-Fi,死活连不上本地 SpringBoot,差点放弃——原来是防火墙!后来插网线解决。


六、下一步学习建议

你已经迈出了 MVVM 的第一步!接下来可以:

  1. 加入 Repository 层:让 ViewModel 不直接调 API,而是通过 Repository 获取数据(支持本地缓存 + 网络)
  2. 用 Room 数据库:把公告缓存到本地,离线也能看
  3. 学习 Jetpack Compose:Google 新一代 UI 框架,和 MVVM 天然契合
  4. 深入 SpringBoot:给公告加上管理后台,让运营同学自己编辑内容!

结语

MVVM 不是魔法,而是一种让代码活得更久的设计方式。作为曾经连“架构”两个字都怕的文科生,我想告诉你:只要动手写,就没有学不会的技术

现在,去跑通你的第一个 MVVM + SpringBoot 项目吧!遇到问题,欢迎回来再读一遍——我当年就是这么过来的 😄

本文约 2480 字,纯手打无图,但希望能照亮你的第一个 App 架构之路。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝