29、Jetpack核心组件:ViewModel、LiveData、Lifecycle、DataBinding的基本使用与原理
各位同学,今天我们来聊聊Jetpack里最核心的四个组件。说实话,这几个东西刚出来的时候,我也觉得“又学新东西?”。但用了一段时间后,我真心觉得——嗯,真香。它们解决了很多我们以前在Android开发中头疼的问题,比如屏幕旋转数据丢失、生命周期管理混乱、UI更新不及时等等。
我个人习惯把ViewModel、LiveData、Lifecycle、DataBinding称为“Jetpack四件套”。它们不是孤立的,而是互相配合的。你想想看,一个典型的MVVM架构里,ViewModel负责数据,LiveData负责通知,Lifecycle负责安全,DataBinding负责绑定。是不是很清晰?
一、ViewModel:数据不丢失的秘密
ViewModel的核心作用,说白了就是在配置变更(比如屏幕旋转)时保住数据。我以前做项目时,最烦的就是用户转一下手机,Activity重建,输入框里的内容全没了。ViewModel就是来解决这个问题的。
核心原理:ViewModel的生命周期比Activity/Fragment长。它会在Activity重建时自动保留,直到Activity真正销毁(比如finish())。
来看一个最简单的用法:
public class MyViewModel extends ViewModel {
private MutableLiveData<String> userName = new MutableLiveData<>();
public LiveData<String> getUserName() {
return userName;
}
public void setUserName(String name) {
userName.setValue(name);
}
}
在Activity里获取ViewModel:
MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
viewModel.getUserName().observe(this, name -> {
textView.setText(name);
});
这里有个坑,我曾经踩过:千万不要把Context传给ViewModel。为什么?因为ViewModel生命周期比Activity长,如果持有Activity的Context,会导致内存泄漏。如果你确实需要Context,可以用AndroidViewModel,它内部持有Application的Context。
注意:ViewModel中不要持有任何View、Activity或Fragment的引用。这是基本原则。
二、LiveData:观察者模式的优雅实现
LiveData是一个可观察的数据持有者。它和普通的观察者模式最大的区别是——它感知生命周期。什么意思?就是如果Activity在后台,LiveData不会去更新UI,避免了空指针和崩溃。
我记得有一次,我在一个后台任务里更新UI,结果Activity已经finish了,直接Crash。后来用了LiveData,再也没出过这种问题。
LiveData的使用很简单:
MutableLiveData<Integer> progress = new MutableLiveData<>();
progress.setValue(50); // 主线程更新
// 或者
progress.postValue(50); // 子线程更新
观察数据:
progress.observe(this, value -> {
progressBar.setProgress(value);
});
这里有个细节:setValue()必须在主线程调用,postValue()可以在子线程调用。我建议你尽量用setValue(),因为postValue()可能会丢失数据——如果你连续post两次,第二次可能会覆盖第一次。
小技巧:如果你需要合并多个LiveData,可以用MediatorLiveData。比如同时监听用户名和头像的变化,然后合并成一个新的LiveData。
三、Lifecycle:生命周期管理的基石
Lifecycle是Jetpack的底层组件。ViewModel和LiveData都依赖它。它的作用就是让组件感知Activity/Fragment的生命周期状态。
你想想看,以前我们写自定义组件时,需要在Activity的onResume、onPause里手动调用方法。有了Lifecycle,组件可以自己监听。
核心概念有两个:
- LifecycleOwner:被观察者,比如Activity、Fragment。
- LifecycleObserver:观察者,比如你的自定义组件。
实现一个自定义观察者:
public class MyObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
// 开始工作
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
// 停止工作
}
}
然后在Activity里添加:
getLifecycle().addObserver(new MyObserver());
这样,你的组件就能自动响应生命周期了。我个人觉得,这是Jetpack最巧妙的设计之一。它把生命周期管理从“被动调用”变成了“主动监听”。
原理简述:Lifecycle内部维护了一个状态机,有INITIALIZED、CREATED、STARTED、RESUMED、DESTROYED等状态。事件(如ON_START)会触发状态迁移。观察者根据事件执行相应逻辑。
四、DataBinding:告别findViewById
DataBinding的作用是把数据和UI直接绑定,省去你写findViewById和setText的功夫。说实话,刚开始我觉得这玩意儿有点“魔法”,用多了才发现——真省事。
首先,在build.gradle里开启:
android {
...
buildFeatures {
dataBinding true
}
}
然后,在布局文件里用<layout>包裹:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="user"
type="com.example.User" />
</data>
<LinearLayout ...>
<TextView
android:text="@{user.name}" />
<Button
android:onClick="@{() -> user.onClick()}" />
</LinearLayout>
</layout>
在Activity里绑定:
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setUser(new User("张三"));
这样,TextView就会自动显示“张三”。如果你修改了User的name属性,UI会自动更新——前提是User类继承BaseObservable或者使用LiveData。
注意:DataBinding和ViewBinding的区别。ViewBinding只是生成绑定类,没有数据绑定能力。DataBinding更强大,但编译速度稍慢。我个人习惯:简单页面用ViewBinding,复杂页面用DataBinding。
五、四件套的协作流程
这四个组件不是孤立的。它们通常这样配合:
- ViewModel 持有数据(LiveData)。
- LiveData 观察数据变化,并通知UI。
- Lifecycle 确保LiveData只在活跃状态更新UI。
- DataBinding 把LiveData直接绑定到XML,省去手动设置。
举个例子:
// ViewModel中
public class MyViewModel extends ViewModel {
public MutableLiveData<String> time = new MutableLiveData<>();
}
// XML中
<TextView android:text="@{viewModel.time}" />
// Activity中
binding.setViewModel(viewModel);
binding.setLifecycleOwner(this); // 关键!让DataBinding感知生命周期
这样,当time的值变化时,TextView会自动更新。而且如果Activity在后台,更新会被延迟,不会崩溃。
核心逻辑图:
六、避坑指南与个人经验
最后,分享几个我实际项目中遇到的坑:
- ViewModel不要存大量数据:比如Bitmap、大列表。ViewModel虽然保活,但Activity销毁时ViewModel也会被清掉。大量数据请用Room或磁盘缓存。
- LiveData的粘性事件:LiveData有一个特性——订阅时会立即收到最后一次的值。这在某些场景下是坑。比如你只想监听一次点击事件,结果一订阅就触发了。解决方案是用
SingleLiveEvent或者EventWrapper。 - DataBinding的编译速度:项目大了,DataBinding会拖慢编译。我建议只在需要双向绑定或复杂表达式的页面使用,简单页面用ViewBinding就够了。
- Lifecycle的线程安全:Lifecycle的方法调用必须在主线程。如果你在子线程里触发生命周期事件,会出问题。这一点官方文档没强调,但我遇到过。
我的建议:如果你是新手,先从ViewModel + LiveData开始,这两个最常用。等熟练了,再引入DataBinding。不要一上来就全上,容易懵。
好了,关于Jetpack四件套的基本使用和原理,就讲到这里。这些东西看起来简单,但用好了能大幅提升代码质量和开发效率。希望你在项目中多实践,遇到问题可以随时翻翻官方文档,或者看看源码——其实源码并不复杂。