1 概述
LiveData 是一个可被观察的数据持有类, 一般的数据类不同, LiveData 是生命周期感知的, 数据类的生命周期可以和其他 App 组件的生命周期保持一致, 例如 Activity,fragment 和 service. 这保证了 LiveData 仅仅会更新处在活动状态的组件.
LiveData 可以被看成观察者模式的实践, LiveData 是一个被观察的对象, 其他组件会订阅对它的观察, 当组件处于 Started 或者 Resumed 则为活跃状态, LiveData 只会通知处于这两者状态的组件更新. 同时希望在组件变为 Destroyed 状态时去自动销毁 LiveData 和组件的绑定, 不至于出现泄漏.
1.1 优势
确保 UI 和数据状态同步
没有内存泄漏
不会因为已经停止的 Activity 导致 crash
不需要手动处理生命周期
组件时刻保持最新数据
支持适当配置更改
如果一个 Activity 或者 fragment 因为例如设备旋转而重新创建, 它会立即接受到最新可获得的数据.
共享资源 多个组件可以共享同一份数据
2 实践
2.1 依赖
LiveData 是 Android 官方架构 Jetpack 的组成部分, 架构组件全部在 google 的 Maven 仓库里, 想要使用可以在项目的 build.gradle 文件里添加 google()依赖.
- allprojects {
- repositories {
- google() // 引入 livedata
- jcenter()
- }
- }
在模块的 build.gradle 文件中加入 lifecycle:extensions 依赖
implementation "android.arch.lifecycle:extensions:1.1.1"
2.2 创建 LiveData 对象
LiveData 通常和 Jetpack 架构下的另一个组件 ViewModel 配合使用, ViewModel 是一个负责为 Activity 或者 Fragment 准备和管理数据的类, 同时处理和应用剩余部分的通信, 注意 ViewModel 仅仅负责管理 UI 上的数据, 其他都无权干涉, 它和组件生命周期绑定, 只有 Activity 结束了, 它才会被销毁.
我们创建一个提供电池电量信息的 ViewModel:
- public class BatteryViewModel extends ViewModel {
- private MutableLiveData<Integer> currentBattery;
- public MutableLiveData<Integer> getCurrentBatteryData() {
- if (currentBattery == null) {
- currentBattery = new MutableLiveData<>();
- }
- return currentBattery;
- }
- }
这里使用了 MutableLiveData 类来保存电量数据, 它继承了 LiveData, 暴露了 setValue,postValue 方法.
- public class MutableLiveData<T> extends LiveData<T> {
- @Override
- public void postValue(T value) {
- super.postValue(value);
- }
- @Override
- public void setValue(T value) {
- super.setValue(value);
- }
- }
2.3 监听 LiveData 对象
写一个 activity 模拟显示电量变化情况, 通常我们要在 onCreate 回调里开始监听 LiveData, 主要出于以下原因:
onCreate 是 activity 创建时的第一个回调, onResume 和 onStart 在 activity 生命周期内会回调多次, 造成调用监听多次形成冗余.
确保 activity 和 fragment 在变成活跃状态进入 started 时可以尽快获得数据更新, 所以要尽早开始监听.
LiveData 在用非活跃状态进入活跃状态时同样可以接受到更新, 但是如果第二次从非活跃状态进入活跃状态, 那么只有当上一次编程活跃态的数据发生变化时才会接受更新.
- public class BatteryActivity extends AppCompatActivity {
- private int battery = 100;
- private BatteryViewModel mBatteryViewModel;
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_livedata_battery);
- // 在当前 activity 范围内创建或者获得 viewmodel 实例
- mBatteryViewModel = ViewModelProviders.of(this).get(BatteryViewModel.class);
- final TextView tvBattery = findViewById(R.id.tv_battery);
- // 设置观察者
- Observer<Integer> batteryOb = new Observer<Integer>() {
- @Override
- public void onChanged(@Nullable Integer integer) {
- tvBattery.setText(String.format("电量:^[0-9]*$", integer));
- }
- };
- // 将数据绑定到观察者
- mBatteryViewModel.getCurrentBatteryData().observe(this, batteryOb);
- }
- }
ViewModelProviders 是 lifecycle:extensions 模块下的类, 首先通过 of(this)创建一个 ViewModelProvider 实例, 再通过 get 方法去获得 (如果有) 或者创建一个 viewmodel, 然后创建一个 Observer, 将它和 viewmodel 绑定, 监听数据的变化, 在 onChanged 回调内实时修改 UI.
2.4 更新 LiveData 数据
监听设置好之后, 下面可以通过修改数据看看 ui 是否被实时修改, 点击开始统计按钮, 让电量减一来模拟掉电情况.
LiveData 更改数据的方法不是 public 类型的, 只在内部自己调用, 所有这里才会使用 MutableLiveData, 他暴露了修改数据的公共方法. 这里修改电量减一就是用到了 setValue 方法.
- findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- mBatteryViewModel.getCurrentBatteryData().postValue(battery--);
- }
- });
可以看到 MutableLiveData 总共有两个修改数据的方法, 他们的区别是什么呢?
setValue 是必须在主线程被调用, 用来修改 LiveData 数据.
postValue 可以在后台线程调用, 它是向线程的观察者发送一个 task, 请求修改数据, 但是如果在主线程执行前调用多次, 则只有最后一次会生效.
3 扩展 LiveData
上面是使用自带的 MutableLiveData, 同样也可以自己定义 LiveData 类.
3.1 自定义 LiveData
自定义一个 BatteryLiveData 类继承自 LiveData, 通过广播去接受系统电池电量, 通过 setValue 将数据设置给 LiveData.
- public class BatteryLiveData extends LiveData<Integer> {
- private Context context;
- private BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- setValue(intent.getIntExtra("level", 0));
- }
- };
- public BatteryLiveData(Context context) {
- this.context = context;
- }
- @Override
- protected void onActive() {
- super.onActive();
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_BATTERY_CHANGED);
- context.registerReceiver(receiver, filter);
- }
- @Override
- protected void onInactive() {
- super.onInactive();
- context.unregisterReceiver(receiver);
- }
- }
需要重写两个方法:
onActive() 当 LiveData 绑定有活跃状态的 observer 时就会调用, 在这里回去注册广播获得电池电量变化.
onInactive() 当 LiveData 没有任何活跃状态 observer 绑定时调用, 取消注册广播.
3.2 获得数据更新
在 activity 里构造 LiveData 实例, 同时调用 observe()方法将 activity 和 LiveData 绑定.
- BatteryLiveData batteryLiveData = new BatteryLiveData(this);
- batteryLiveData.observe(this, new Observer<Integer>() {
- @Override
- public void onChanged(@Nullable Integer integer) {
- tvBattery.setText(integer.toString());
- }
- });
3.3 共享资源
文章一开始讲到 LiveData 的优势之一就是共享资源, 可以将 LiveData 设计成单例模式, 在任何需要的地方调用 observe()绑定监听.
- public class BatteryLiveData extends LiveData<Integer> {
- ...
- @MainThread
- public static BatteryLiveData getInstance(Context context) {
- if (sInstance == null) {
- sInstance = new BatteryLiveData(context);
- }
- return sInstance;
- }
- private BatteryLiveData(Context context) {
- this.context = context;
- }
- ...
- }
- BatteryLiveData.getInstance(this).observe(this, new Observer<Integer>() {
- @Override
- public void onChanged(@Nullable Integer integer) {
- tvBattery.setText(integer.toString());
- }
- });
4 LiveData 转换
4.1 map
map 是将一个 LiveData 转换成另一个 LiveData.
- Transformations.map(batteryLiveData, new Function<Integer, String>() {
- @Override
- public String apply(Integer input) {
- return input + "%";
- }
- });
4.2 switchMap
第二个参数接收一个方法, 通过方法将传入的第一个参数 LiveData 转换成另一个 LiveData.
- Transformations.switchMap(sInstance, new Function<Integer, LiveData<? extends String>>() {
- @Override
- public LiveData<? extends String> apply(Integer input) {
- return ...;
- }
- });
5 源码解析
下面来分析一下 LiveData 的关键源码. 先从 LiveData 类开始: LiveData 里面主要有几个上面用到的方法, observe,setValue,postValue,onActive,onInactive 等, 挨个来分析.
- 5.1 observe()
- @MainThread
- public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
- if (owner.getLifecycle().getCurrentState() == DESTROYED) {
- // ignore
- return;
- }
- LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
- ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
- if (existing != null && !existing.isAttachedTo(owner)) {
- throw new IllegalArgumentException("Cannot add the same observer"
- + "with different lifecycles");
- }
- if (existing != null) {
- return;
- }
- owner.getLifecycle().addObserver(wrapper);
- }
- public interface LifecycleOwner {
- @NonNull
- Lifecycle getLifecycle();
- }
observe 有两个参数, 第一个是 LifecycleOwner, 和等都实现了该接口, 因此我们在调用的时候就可以直接传入 this, 它里面有一个方法可以获得当前的 Lifecycle 实例, Lifecycle 里面保存了和生命周期相对应的状态.
observe 方法首先先判断当前状态是不是 DESTROYED, 如果是就可以完全忽略, 因为已经说过只对处于活跃状态的组件做更新; 接着将 owner observer 构造成 LifecycleBoundObserver 实例, 这是一个内部类, 里面有关于状态变换的一系列操作, 待会详细分析; 然后将 observer 和 wrapper 存入 map 缓存中, 如果 observer 缓存已存在并且已经和另一个 LifecycleOwner 绑定, 则抛出异常; 如果缓存已经存在则直接忽略; 最后调用 addObserver 方法将 LifecycleBoundObserver 实例和 LifecycleOwner 绑定. 而 addObserver 是调用了 LifecycleRegistry 类的实现.
- 5.2 ObserverWrapper
- private abstract class ObserverWrapper {
- final Observer<T> mObserver;
- boolean mActive;
- int mLastVersion = START_VERSION;
- ObserverWrapper(Observer<T> observer) {
- mObserver = observer;
- }
- abstract boolean shouldBeActive();
- boolean isAttachedTo(LifecycleOwner owner) {
- return false;
- }
- void detachObserver() {
- }
- void activeStateChanged(boolean newActive) {
- if (newActive == mActive) {
- return;
- }
- // immediately set active state, so we'd never dispatch anything to inactive
- // owner
- mActive = newActive;
- boolean wasInactive = LiveData.this.mActiveCount == 0;
- LiveData.this.mActiveCount += mActive ? 1 : -1;
- // 过去是 inactive, 现在是 active
- if (wasInactive && mActive) {
- onActive();
- }
- // 过去没有订阅, 并且现在是 inactive
- if (LiveData.this.mActiveCount == 0 && !mActive) {
- onInactive();
- }
- // 现在是 active
- if (mActive) {
- dispatchingValue(this);
- }
- }
- }
- class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
- ...
- @Override
- public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
- if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
- removeObserver(mObserver);
- return;
- }
- activeStateChanged(shouldBeActive());
- }
- }
ObserverWrapper 里面封装了关于状态的操作, 包括判断是否处于活跃状态, observer 是否绑定到 lifecycleowner 以及更改 activity 状态等.
activeStateChanged 首先判断新来的状态和旧状态是否相同, 相同则忽略, 然后判断 LiveData 上的活跃态的数量是否为 0, 为 0 说明之前处于 Inactive, 然后统计现在的订阅数, 接着就是三个 if 判断, 注释在代码里. 正式这三个判断, LiveData 可以接收到 onActive 和 onInactive 的回调.
dispatchingValue(this)是当状态变为 active 时调用, 用来更新数据. 里面会用到 considerNotify 方法.
- 5.3 setValue postValue
- private final Runnable mPostValueRunnable = new Runnable() {
- @Override
- public void run() {
- Object newValue;
- synchronized (mDataLock) {
- newValue = mPendingData;
- mPendingData = NOT_SET;
- }
- //noinspection unchecked
- setValue((T) newValue);
- }
- };
- protected void postValue(T value) {
- boolean postTask;
- synchronized (mDataLock) {
- postTask = mPendingData == NOT_SET;
- mPendingData = value;
- }
- if (!postTask) {
- return;
- }
- ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
- }
- @MainThread
- protected void setValue(T value) {
- assertMainThread("setValue");
- mVersion++;
- mData = value;
- dispatchingValue(null);
- }
- private void considerNotify(ObserverWrapper observer) {
- if (!observer.mActive) {
- return;
- }
- if (!observer.shouldBeActive()) {
- observer.activeStateChanged(false);
- return;
- }
- if (observer.mLastVersion>= mVersion) {
- return;
- }
- observer.mLastVersion = mVersion;
- //noinspection unchecked
- observer.mObserver.onChanged((T) mData);
- }
setValue 会调用 dispatchingValue 方法, 接着调用 considerNotify, 在最后调用 onChange()回调, 就能收到数据变化.
postValue 之前说过是往主线程发送事件, 同时加锁保持占用, 防止多线程并发竞争导致的数据错误, 因为每次 postValue 成功都会对 mPendingData 重置为 NOT_SET. 然后想主线程发送 Runnable 对象, Runnable 实例的 run 方法会执行 setValue 在主线程修改数据.
6 参考资料
LiveData Overview
来源: https://juejin.im/post/5c73c0ede51d450da463638f