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。

五、四件套的协作流程

这四个组件不是孤立的。它们通常这样配合:

  1. ViewModel 持有数据(LiveData)。
  2. LiveData 观察数据变化,并通知UI。
  3. Lifecycle 确保LiveData只在活跃状态更新UI。
  4. 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在后台,更新会被延迟,不会崩溃。

核心逻辑图:

Jetpack 四件套协作流程 ViewModel 持有数据 + 业务逻辑 LiveData 观察数据变化 Lifecycle 感知生命周期 DataBinding UI自动更新 1. ViewModel 创建 LiveData 并暴露数据 2. LiveData 观察数据变化,自动通知观察者 3. Lifecycle 确保通知只在活跃状态(前台)执行 4. DataBinding 将 LiveData 绑定到 XML,自动更新 UI

六、避坑指南与个人经验

最后,分享几个我实际项目中遇到的坑:

  • ViewModel不要存大量数据:比如Bitmap、大列表。ViewModel虽然保活,但Activity销毁时ViewModel也会被清掉。大量数据请用Room或磁盘缓存。
  • LiveData的粘性事件:LiveData有一个特性——订阅时会立即收到最后一次的值。这在某些场景下是坑。比如你只想监听一次点击事件,结果一订阅就触发了。解决方案是用SingleLiveEvent或者EventWrapper
  • DataBinding的编译速度:项目大了,DataBinding会拖慢编译。我建议只在需要双向绑定或复杂表达式的页面使用,简单页面用ViewBinding就够了。
  • Lifecycle的线程安全:Lifecycle的方法调用必须在主线程。如果你在子线程里触发生命周期事件,会出问题。这一点官方文档没强调,但我遇到过。

我的建议:如果你是新手,先从ViewModel + LiveData开始,这两个最常用。等熟练了,再引入DataBinding。不要一上来就全上,容易懵。

好了,关于Jetpack四件套的基本使用和原理,就讲到这里。这些东西看起来简单,但用好了能大幅提升代码质量和开发效率。希望你在项目中多实践,遇到问题可以随时翻翻官方文档,或者看看源码——其实源码并不复杂。

公众号:蓝海资料掘金营,微信deep3321