1. LiveData与ViewModel初探:什么是LiveData?什么是ViewModel?为什么需要它们?MVVM架构简介。
各位同学好,我是你们的老朋友。今天咱们正式开始《Kotlin Android LiveData与ViewModel状态管理实战》的第一章。
说实话,每次带新人或者做技术分享时,我总会被问到同一个问题:「为什么现在的Android开发非要搞LiveData和ViewModel?以前用回调、用Handler不也挺好的吗?」
嗯,这个问题问得好。咱们今天就把这事儿彻底聊透。
1.1 一个让我头疼的真实场景
先说说我自己的经历。几年前我接手过一个项目,是个新闻阅读App。代码里充斥着大量的AsyncTask、Handler、还有各种回调嵌套。当时有个需求:用户在列表页点击新闻,进入详情页,然后从详情页返回时,列表页要自动刷新。
你猜怎么着?
因为Activity重建(比如屏幕旋转),列表页的数据全丢了。用户返回时看到的是空白页面。更糟的是,后台的异步任务还在跑,结果回调到了一个已经被销毁的Activity上——直接崩溃。
这种问题,说白了就是生命周期管理混乱和数据与UI耦合太紧导致的。
那LiveData和ViewModel就是来解决这些问题的。
1.2 什么是LiveData?
LiveData,从名字就能看出来——它是「活着的」数据。
官方定义:LiveData是一个可观察的数据持有者类。它感知组件的生命周期。
我换个说法你更好理解:
LiveData就像是一个智能广播站。它手里攥着一份数据,然后它知道谁在听它广播。更重要的是,它知道每个听众当前是「活跃」还是「非活跃」状态。
- 如果听众在前台(活跃状态),数据一变,立刻通知。
- 如果听众在后台(非活跃状态),数据变了,先记着,等听众回到前台再通知。
- 如果听众已经「死」了(比如Activity被销毁),自动取消订阅,绝不通知。
这就避免了那个让我头疼的问题——回调到已销毁的Activity。
核心特性:
- 数据驱动UI:数据变了,UI自动更新
- 生命周期感知:自动管理订阅,避免内存泄漏
- 不会因为屏幕旋转而丢失数据(配合ViewModel)
- 数据共享:多个Fragment可以观察同一个LiveData
来个最简单的代码示例:
// 创建一个LiveData,持有用户年龄数据
val userAge = MutableLiveData<Int>()
// 在Activity或Fragment中观察它
userAge.observe(this) { age ->
// 当age变化时,自动更新UI
textView.text = "年龄:$age"
}
// 更新数据,UI会自动刷新
userAge.value = 25
你看,就这么几行代码,就实现了数据变化自动更新UI。不用手动刷新,不用担心中间状态。
1.3 什么是ViewModel?
ViewModel,直译就是「视图模型」。它存在的意义很简单:帮Activity和Fragment扛住配置变更。
你想想看,Activity在屏幕旋转时会被销毁重建。那它里面的数据呢?全没了。以前我们怎么处理?用onSaveInstanceState()存Bundle,但Bundle能存的数据类型有限,大对象根本存不了。
ViewModel就是来解决这个痛点的。
ViewModel的生命周期比Activity长。只要Activity没有真正finish,ViewModel就一直活着。屏幕旋转?ViewModel不受影响,数据完好无损。
我的个人习惯:把所有与UI相关的数据都放在ViewModel里。Activity和Fragment只负责展示和交互,不负责存数据。这样哪怕Activity被重建100次,数据依然在。
看个例子:
class UserViewModel : ViewModel() {
// 用户数据,放在ViewModel里
private val _user = MutableLiveData<User>()
val user: LiveData<User> get() = _user
fun loadUser(userId: String) {
// 模拟网络请求
viewModelScope.launch {
val result = api.fetchUser(userId)
_user.value = result
}
}
}
// 在Activity中使用
class UserActivity : AppCompatActivity() {
private val viewModel: UserViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 观察数据
viewModel.user.observe(this) { user ->
// 更新UI
bindUI(user)
}
// 加载数据
viewModel.loadUser("123")
}
}
注意看,by viewModels()这个委托。它保证了ViewModel的实例在屏幕旋转前后是同一个对象。数据自然就不会丢了。
1.4 为什么需要它们?
说白了,就三个字:解耦、存活、安全。
| 问题 | 传统方式 | LiveData + ViewModel |
|---|---|---|
| 屏幕旋转数据丢失 | 用Bundle保存,麻烦且有限 | ViewModel自动存活,数据不丢 |
| 异步回调空指针 | 手动判空,容易遗漏 | LiveData自动感知生命周期,安全 |
| UI与业务逻辑耦合 | Activity里写网络请求、数据库操作 | ViewModel统一管理,Activity只负责UI |
| 多个Fragment共享数据 | 用接口回调,代码繁琐 | 共享同一个ViewModel,简单直接 |
我在项目中遇到过最典型的一个案例:一个电商App的商品详情页,包含商品信息、评论、推荐三个Fragment。这三个Fragment都需要访问同一个商品ID和用户信息。
如果用传统方式,你得在Activity里维护这些数据,然后通过接口传给Fragment。一旦Activity重建,全乱套。
用ViewModel呢?直接让三个Fragment共享同一个ViewModel实例。数据统一管理,生命周期统一感知。代码量减少一半,稳定性提升一倍。
1.5 MVVM架构简介
LiveData和ViewModel,其实是MVVM架构在Android中的具体实现。
MVVM的全称是Model-View-ViewModel。它把代码分成三层:
- Model:数据层。包括网络请求、数据库、文件IO等。说白了就是「数据从哪里来」。
- View:视图层。就是Activity、Fragment、各种View。它只负责「怎么展示」和「用户点了哪里」。
- ViewModel:视图模型层。它是View和Model之间的桥梁。负责从Model拿数据,加工处理,然后交给View展示。
这三层的关系,我画了张图,你一看就明白:
这张图你看懂了吗?数据是单向流动的。View只负责展示和触发事件,不直接操作数据。ViewModel负责处理逻辑和持有数据。Model只负责提供原始数据。
这样做的好处是什么?
- 可测试性:ViewModel不依赖Android组件,可以纯单元测试。
- 可维护性:每一层职责清晰,改UI不影响数据逻辑。
- 可复用性:同一个ViewModel可以给多个View用。
注意:千万不要在ViewModel里持有Activity或View的引用。我曾经见过有人把Context传到ViewModel里,结果导致内存泄漏。ViewModel的生命周期比Activity长,持有Activity引用会导致Activity无法被回收。
正确的做法是:如果需要Context,使用AndroidViewModel(它持有Application级别的Context)。
1.6 一个小总结
好了,咱们今天聊了不少。
LiveData是那个「智能广播站」,自动感知生命周期,数据变了就通知UI。
ViewModel是那个「数据保险箱」,屏幕旋转也不丢数据,帮Activity扛住配置变更。
MVVM架构就是让这三层各司其职,代码清晰又好维护。
嗯,第一章的内容就到这里。记住我今天说的那个新闻App的教训——别让数据跟着Activity一起「死掉」。用LiveData和ViewModel,让你的数据「活」起来。
我的建议:从今天开始,写新功能时强制自己用ViewModel + LiveData。哪怕只是一个简单的计数器。用多了,你就知道它们有多香了。
公众号:蓝海资料掘金营,微信deep3321