LiveData

138 阅读7分钟

LiveData是什么

基于观察者模式

LiveData是一种持有可被观察数据的类。LiveData需要一个观察者对象,一般是Observer类的具体实现。当观察者的生命周期处于STARTED或RESUMED状态时,LiveData会通知观察者数据变化。

感知生命周期

和其他可被观察的类不同的是,LiveData是有生命周期感知能力的,这意味着它可以在activities, fragments, 或者 services生命周期是活跃状态时更新这些组件。那么什么是活跃状态呢?就是STARTED和RESUMED就是活跃状态,只有在这两个状态下LiveData是会通知数据变化的。

自动解除数据订阅

要想使用LiveData(或者这种有可被观察数据能力的类)就必须配合实现了LifecycleOwner的对象使用。在这种情况下,当对应的生命周期对象DESTORY时,才能移除观察者。这对Activity或者Fragment来说显得尤为重要,因为他们可以在生命周期结束的时候立刻解除对数据的订阅,从而避免内存泄漏等问题。

LiveData的优势

UI和实时数据保持一致

因为LiveData采用的是观察者模式,这样一来就可以在数据发生改变时获得通知,更新UI。

不会发生内存泄露

观察者被绑定到组件的生命周期上,当被绑定的组件销毁(onDestroy)时,观察者会立刻自动清理自身的数据。

不会再产生由于Activity处于stop状态而引起的崩溃

例如:当Activity处于后台状态时,是不会收到LiveData的任何事件的。

不需要再解决生命周期带来的问题

LiveData可以感知被绑定的组件的生命周期,只有在活跃状态才会通知数据变化。

实时数据刷新

当组件处于活跃状态或者从不活跃状态到活跃状态时总是能收到最新的数据

解决Configuration Change问题

我们知道,当你把数据存储在组件中时,当configuration change(比如语言、屏幕方向变化)时,组件会被recreate,然而系统并不能保证你的数据能够被恢复的。当我们采用LiveData保存数据时,因为数据和组件分离了。当组件被recreate,数据还是存在LiveData中,并不会被销毁。

数据共享

如果对应的LiveData是单例的话,就能在app的组件间分享数据。这部分详细的信息可以参考继承LiveData

使用LiveData

看下官网的例子。

public class LiveDataActivity extends BaseActivity {

    private NameViewModel model;
    private TextView mText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.live_data);
        initView();
        // Other code to setup the activity...

        // Get the ViewModel.
        model = new ViewModelProvider(this).get(NameViewModel.class);

        // Create the observer which updates the UI.
        final Observer<String> nameObserver = new Observer<String>() {
            @Override
            public void onChanged(@Nullable final String newName) {
                // Update the UI, in this case, a TextView.
                mText.setText(newName);
            }
        };

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        model.getCurrentName().observe(this, nameObserver);
        initView();
    }

    private void initView() {
        mText = (TextView) findViewById(R.id.text);
    }

    public class NameViewModel extends ViewModel {

        // Create a LiveData with a String
        private MutableLiveData<String> currentName;

        public MutableLiveData<String> getCurrentName() {
            if (currentName == null) {
                currentName = new MutableLiveData<String>();
            }
            return currentName;
        }

// Rest of the ViewModel...
    }
}

数据传递

实际上LiveData传递数据的方法也是通过Handler。在postValue()方法中,LiveData调用ArchTaskExecutor.postToMainThread(),将一个Runnable对象传递给主线程。这个Runnable对象调用setValue()对数据进行更新。

更新数据的时候,LiveData首先将版本号加1,然后遍历观察者。如果观察者处于活跃状态(Lifecycle.State是STARTED或RESUMED),并且观察者的版本号小于LiveData,LiveData会调用观察者的onChanged()方法进行通知。

生命周期管理

当观察者的生命周期不是STARTED或RESUMED时,数据更新不会进行通知。这是怎么实现的呢?在调用observe()时,第一个参数是LifecycleOwner,第二个参数是Observer。LiveData建立一个LifecyleBoundObserver对象,将这两个参数绑定到一起,来接收Lifecycle的生命周期更新和LiveData的数据更新。

通过实现LifecycleEventObserver接口 来实现Lifecycle的生命周期更新。

源码分析

observe方法

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
    //当前绑定的组件(activity或者fragment)状态为DESTROYED的时候, 则会忽视当前的订阅请求
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    //创建生命周期感知的观察者包装类
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    //如果指定的键尚未与某个值关联,则将其与给定的值关联
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    //对应观察者只能与一个owner绑定
    if (existing != null && !existing.isAttachedTo(owner)) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    //lifecycle注册
    //添加一个LifecycleObserver,它将在LifecycleOwner更改状态时得到通知
    owner.getLifecycle().addObserver(wrapper);
}

setValue源码分析

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    // 这里的 mVersion,它本问题关键,每次更新数据都会自增,默认值是 -1。
    mVersion++;
    mData = value;
    dispatchingValue(null);
}
void dispatchingValue(@Nullable ObserverWrapper initiator) {
        // mDispatchingValue的判断主要是为了解决并发调用dispatchingValue的情况
        // 当对应数据的观察者在执行的过程中, 如有新的数据变更, 则不会再次通知到观察者
        // 所以观察者内的执行不应进行耗时工作
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
              	// 这里
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                  	// 这里
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

dispatchingValue 这里分两种情况:ObserverWrapper不为null和ObserverWrapper为null

  • ObserverWrapper不为null 的情况。LifecycleBoundObserver.onStateChanged 方法里调用了 activeStateChanged ,而该方法调用dispatchingValue(this);传入了 this ,也就是 LifecycleBoundObserver ,这时候不为 null 。也就是说Owner生命周期改变触发的流程就是这种情况,这种情况下,只会通知跟该 Owner 绑定的 Observer。

  • ObserverWrapper为null 的情况。经过分析发现在setValue方法中调用dispatchingValue(null)传递了空对象,这个时候的流程则会通知 active 的mObservers。LiveData自己数据改变

private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
    // 检查最新的状态b4调度。也许它改变了状态,但我们还没有得到事件。
    // 我们还是先检查观察者。活动,以保持它作为活动的入口。
    // 因此,即使观察者移动到一个活动状态,如果我们没有收到那个事件,我们最好不要通知一个更可预测的通知顺序。
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    
    //注意认真看下面的代码
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    //noinspection unchecked
    observer.mObserver.onChanged((T) mData);
}

private abstract class ObserverWrapper {
    final Observer<T> mObserver;
    boolean mActive;
    int mLastVersion = START_VERSION;
    //省略部分代码
    void activeStateChanged(boolean newActive) {
        if (newActive == mActive) {
            return;
        }
        // 当observer的状态从active->inactive, 或者inactive->active的时候走以下流程
        // owner
        mActive = newActive;
        boolean wasInactive = LiveData.this.mActiveCount == 0;
        LiveData.this.mActiveCount += mActive ? 1 : -1;
        if (wasInactive && mActive) {
            onActive();
        }
        if (LiveData.this.mActiveCount == 0 && !mActive) {
            onInactive();
        }
        //当observer是从inactive->active的时候,需要通知到观察者
        if (mActive) {
            dispatchingValue(this);
        }
    }
}

observeForever源码

@MainThread
public void observeForever(@NonNull Observer<T> observer) {
    // 创建一个AlwaysActiveObserver对象
    AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    //刷新数据
    wrapper.activeStateChanged(true);
}

当LiveData包装的数据发生变化时,无论页面处于什么状态,observeForever()都能收到通知。所以,在使用完之后,一定要记得调用removeObserver()方法来停止对LiveData的观察,否则LiveData会一直处于激活状态,你的Activity永远不会被系统自动回收。

发送消息事件流程

  • setValue ——> dispatchingValue(null) ——> considerNotify(注意,这里是个for迭代器循环,表示通知所有观察者) ——> onChanged

LiveData和EventBus

EventBus 是业界知名的通信类总线库,但它也存在许多被人诟病的缺点:

  1. 需要手动的注册和反注册,稍不小心可能会造成内存泄露。
  2. 使用 EventBus 出错时难以跟踪出错的事件源。
  3. 每个事件都要定义一个事件类,容易造成类膨胀。

而通过 LiveData 实现的 LiveDataBus 的具有以下优点:

  1. 具有生命周期感知能力,不用手动注册和反注册。
  2. 具有唯一的可信事件源。
  3. 以字符串区分每一个事件,避免类膨胀。
  4. LiveData 为 Android 官方库,更加可靠。

问题

参考: