LiveData的工作原理分析

Posted mChenys

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LiveData的工作原理分析相关的知识,希望对你有一定的参考价值。

一、简介

LiveData是一个数据持有类,它可以通过添加观察者被其他组件观察其变更。不同于普通的观察者,它最重要的特性就是遵从应用程序的生命周期,如在Activity中如果数据更新了但Activity已经是destroy状态,LivaeData就不会通知Activity(observer)。当然LiveData的优点还有很多,如不会造成内存泄漏等。LiveData通常会配合ViewModel来使用,ViewModel负责触发数据的更新,更新会通知到LiveData,然后LiveData再通知活跃状态的观察者。

二、数据监听源码分析

2.1 LiveData的observer方法分析

直接从observe方法入手

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) 
    // 判断是否在主线程,不是则报错
    assertMainThread("observe");
    if (owner.getLifecycle().getCurrentState() == DESTROYED) 
        // ignore 如果Activity/fragment已经销毁了,那么忽略
        return;
    
     // 重点代码,包装了一个LifecycleBoundObserver,将外部出入的owner和observer封装了一层
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    // 重点代码,mObservers=SafeIterableMap<Observer<? super T>, ObserverWrapper>,可以把它看作Map
    // 这里的目的就是尝试保存到map,返回值可以用来判断是第一次添加还是说之前已经添加过
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && !existing.isAttachedTo(owner)) 
        // 如果返回值存在,那么说明不是第一次put到Map缓存中,那么避免重复添加,这里直接抛出异常了
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    
    if (existing != null) 
        // 已经添加过观察者,直接返回
        return;
    
    // 如果owner没有添加过观察者,那么才添加,注意这里添加的并不是我们外面传入的,而已经过包装过后的LifecycleBoundObserver
    // 当添加了Lifecycle的观察者后,LifecycleBoundObserver就能感知owner的生命周期了
    owner.getLifecycle().addObserver(wrapper);

2.2 LifecycleBoundObserver源码分析

下面就来看看LifecycleBoundObserver到底是何方神圣

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver 
    @NonNull
    final LifecycleOwner mOwner; // 真正的外部传入的LifecycleOwner

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) 
        super(observer); // 这里将外部传入的观察者传给了父类ObserverWrapper
        mOwner = owner;
    

    @Override
    boolean shouldBeActive() 
        // 这里状态要start之后才表示激活了
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    

    // 实现GenericLifecycleObserver的接口方法,由LifeCycler回调
    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) 
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) 
            // 当目标不可见的时候调用liveData的removeObserver方法,将外部传入的观察者移除掉
            removeObserver(mObserver);
            return;
        
        // 重点代码:通知父类ObserverWrapper状态变化,后面会介绍
        activeStateChanged(shouldBeActive());
    

    @Override
    boolean isAttachedTo(LifecycleOwner owner) 
        // 是否添加到目标owner中
        return mOwner == owner;
    

    @Override
    void detachObserver() 
        // 目标lifeCycle异常观察者,注意传入的是this,也就是包装后的
        mOwner.getLifecycle().removeObserver(this);
    

上面代码并不多,LifecycleBoundObserver 继承自LiveData的内部类ObserverWrapper 并实现了 GenericLifecycleObserver接口,而 GenericLifecycleObserver 接口又继承自 LifecycleObserver 接口,那么根据 Lifecycle 的特性,实现了LifecycleObserver接口并且加入 LifecycleOwner 的观察者里就可以感知或主动获取 LifecycleOwner 的状态。

2.3 ObserverWrapper源码分析

我们来看看ObserverWrapper源码

// 这是定义在LiveData内部的抽象类
private abstract class ObserverWrapper 
    // 这里的观察者其实就是我们外面传入的,也就是它的子类LifecycleBoundObserver的构造方法赋值的
    final Observer<? super T> mObserver;
    boolean mActive; // 标记是否激活了
    // 重点代码,标记最后一次发送数据的版本,默认是-1
    int mLastVersion = START_VERSION;

    ObserverWrapper(Observer<? super T> observer) 
        mObserver = observer; // 子类继承后需要调用usper来赋值
    
    // 抽象方法,由子类LifecycleBoundObserver实现
    abstract boolean shouldBeActive();

    boolean isAttachedTo(LifecycleOwner owner) 
        return false;// 默认是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;
        if (wasInactive && mActive) 
            // 回调给LiveData,当前是激活状态
            onActive();
        
        if (LiveData.this.mActiveCount == 0 && !mActive) 
            // 回调给LiveData,当前是非激活状态
            onInactive();
        
        if (mActive) 
            // 如果激活了,调用下面方法进行分发,后面会重点介绍,这个方法是LiveData的方法
            dispatchingValue(this);
        
    

2.4 LifecycleEventObserver接口分析

来看看LifecycleEventObserver接口,很简单,只是继承了LifecycleObserver,并且提供了一个方法用来通知状态变更

public interface LifecycleEventObserver extends LifecycleObserver 
    /**
     * Called when a state transition event happens.
     *
     * @param source The source of the event
     * @param event The event
     */
    void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);

分析到这里,我们可以清楚的知道,当我们调用LiveData的observer的时候其实是调用了owner的getLifecycle().addObserver添加了一个经过包装后的LifecycleBoundObserver观察者

三、数据发送源码分析

3.1 LiveData的postValue/setValue方法分析

看完了上面观察者的注册分析后,那么我们的LiveData什么时候会通知观察者呢?不用想,肯定是数据更新的时候,而数据的更新是我们代码自己控制的,如请求网络返回User信息后,我们会主动将User放入MutableLiveData中,这个时候就要用到postValue或者setValue方法了,由于LiveData是一个抽象类且这2个方法都是protected的,而它的子类MutableLiveData中是重写了这2个方法的.

public class MutableLiveData<T> extends LiveData<T> 
    // 带参数构造方法
    public MutableLiveData(T value) 
        super(value);
    
    public MutableLiveData() 
        super();
    

    @Override
    public void postValue(T value) 
        super.postValue(value); // 调用super方法
    

    @Override
    public void setValue(T value) 
        super.setValue(value); // 调用super方法
    

来看看父类做了啥

static final int START_VERSION = -1;
private volatile Object mData; // 维护的数据
private int mVersion = START_VERSION; // 维护的版本,每次发送数据都会自增

// 运行在子线程
protected void postValue(T value) 
    boolean postTask;
    synchronized (mDataLock) 
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    
    if (!postTask) 
        return;
    
    /// 发送到主线程中
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);


private final Runnable mPostValueRunnable = new Runnable() 
    @SuppressWarnings("unchecked")
    @Override
    public void run() 
        Object newValue;
        synchronized (mDataLock) 
            newValue = mPendingData;
            mPendingData = NOT_SET;
        
        // 最终还是调用下面的setValue方法发送数据
        setValue((T) newValue);
    
;

// 运行在主线程
@MainThread
protected void setValue(T value) 
    assertMainThread("setValue"); // 判断是否在主线程
    mVersion++; // 重点代码,版本自增
    mData = value; // 保存数据
    // 重点方法
    dispatchingValue(null);

3.2 LiveData的dispatchingValue方法分析

可以看到调用 dispatchingValue()方法并传入null,表示将数据分发给各个观察者, 下面来分析此方法的具体逻辑

private boolean mDispatchingValue; // 标记当前是否正在分发数据

void dispatchingValue(@Nullable ObserverWrapper initiator) 
    if (mDispatchingValue) 
        mDispatchInvalidated = true;
        return;
    
    // 更新标记
    mDispatchingValue = true;
    do 
        mDispatchInvalidated = false;
        if (initiator != null) 
            // 标注1:如果传入的不是null,那么调用下面的方法通知观察者
            // 还记得上面分析ObserverWrapper源码的activeStateChanged方法吗
            // 没错当LifecycleBoundObserver监听到owner状态变化后会调用其父类ObserverWrapper的activeStateChanged方法,
            // 然后activeStateChanged方法会在mActive=true的时候调用considerNotify方法
            considerNotify(initiator);
            initiator = null;
         else 
            // initiator=null进来
            // 否则遍历所有的观察者,还记得这里的map吗,他就是mObservers,key=observer,value=LifecycleBoundObserver
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) 
                //标注2: 通知所有的LifecycleBoundObserver
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) 
                    break;
                
            
        
     while (mDispatchInvalidated);
    mDispatchingValue = false;

3.3 LiveData的considerNotify方法分析

从标注1可以看出,dispatchingValue()参数传null和不传null的区别就是如果传null将会通知所有的观察者,反之仅仅通知传入的观察者。我们直接看标注2,通知所有的观察者通过遍历 mObservers ,将所有的 ObserverWrapper 拿到,实际上就是我们上面提到的 LifecycleBoundObserver,通知观察者调用considerNotify()方法,这个方法就是通知的具体实现了。

private void considerNotify(ObserverWrapper observer) 
    if (!observer.mActive) 
        // 如果LifecycleBoundObserver维护的状态,切切来说是它的父类ObserverWrapper的mActive=false,那么忽略数据的发送
        return;
    
    // 这里通过observer.shouldBeActive间接的判断owner的状态,这里主动调用一次也是为了保证状态更加精确
    // 因为上面的observer.mActive判断是被动监听的
    if (!observer.shouldBeActive())  
        // 如果owner的状态不可见,那么通知状态变化,更新的observer.mActive的值=false
        observer.activeStateChanged(false);
        return;
    
    if (observer.mLastVersion >= mVersion) 
        // 重点方法,对比LifecycleBoundObserver的mLastVersion版本和LiveData的版本mVersion,如果相同或者大于LiveData的,则忽略数据的发送
        return;
    
    // 上面经过重重筛选后来到这里,说明是需要发送数据,更新mLastVersio的版本
    // 而mVersion的值在上面分析postValue方法的时候我们知道每次调用的时候都会自增
    observer.mLastVersion = mVersion;
    // 通知真正的观察者,也就是我门注入的观察者,它维护在LifecycleBoundObserver中
    observer.mObserver.onChanged((T) mData);

如果观察者不是活跃状态,将不会通知此观察者,看最后一行,observer.mObserver.onChanged((T) mData),observer.mObserver就是我们调用LiveData的observer()方法传入的 Observer,然后调用 Observer 的 onChanged((T) mData)方法,将保存的数据mData传入,也就实现了更新。在看下我们实现的Observer:

viewModel.getUser().observe(MainActivity.this, new Observer<User>() 
    @Override
    public void onChanged(@Nullable User user) 
        if (user != null) 
            tvUser.setText(user.toString());
        
    
);

如果哪个控件要根据user的变更而及时更新,就在onChanged()方法里处理就可以了。到这里,LiveData已经能够分析完了,其实LiveData的实现还是要依赖于Lifecycle。

四、LiveData的粘性事件

4.1 何为粘性事件

即发射的事件如果早于注册,那么注册之后依然可以接收到的事件称为粘性事件。

4.2 发生粘性事件的原因

粘性事件通常会出现在多个页面共用同一个单例的LiveData对象的场景,究其原因就是因为LiveData的mVersion大于LifecycleBoundObserver的mLastVersion导致的。因为LiveData的mVersion是用来标记发送数据的次数的,每调用一次postValue或者setValue方法就会让mVersion自增一次,而前面分析源码的时候我门知道当mVersion > mLastVersion的时候就会将数据发送给我们设置的观察者的onChanged方法。

至于为什么初次设置监听会出现mVersion > mLastVersion的情况呢?
首先我需要说明下,mVersion和mLastVersion的默认值都是等于START_VERSION常量,它的值就是-1, 因此我们第一次使用LiveData肯定是mVersion=mLastVersion=-1的,因此首次设置observer进行监听的时候是不会出现粘性事件。

但是,如果现在有2个Activity页面分别是A页面和B页面,A和B页面都是同时使用一个单例的LiveData对象,下面开始分析:

  • A页面设置监听,同时发送一次数据,那么LiveData的mVersion+1后变成0, 同时A页面设置observer会收到通知,因为LifecycleBoundObserver第一次添加到Lifecycler的时候,它的mLastVersion=-1,因此满足mVersion>mLastVersion, 所有A页面能收到通知,而此时B页面还没有打开,所以并没有触发添加监听的操作,因此B收不到通知。

  • A页面跳到B页面,B页面在onCreate使用同一个LiveData进行事件的observer监听,它会立刻收到粘性事件,因为此时的LiveData的mVersion变成了0, 而B页面Lifecycler在注册observer的时候也是一个新的LifecycleBoundObserver, 即mLastVersion是-1,因此满足mVersion>mLastVersion,所以B页面收到粘性事件。

4.3 从源码角度分析粘性事件

由于粘性事件是在设置observer的时候发生,因此我们还是从LiveData的observer方法入手分析

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) 
        assertMainThread("observe");
        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);
    

此处getLifeCycle获取的对象是LifecycleRegistry对象,查看AppcompatActivity的getLifecycle方法就可以知道原因了,它最终会调用ComponentActivity的getLifecycle方法

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner 
    ...
    // 这里可知mLifecycleRegistry就是LifecycleRegistry对象
    private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
    
   public Lifecycle getLifecycle() 
       // 返回一个mLifecycleRegistry对象
       return mLifecycleRegistry;
   

因此,我们需要来分析LifecycleRegistry的addObserver方法

@Override
public void addObserver(@NonNull LifecycleObserver observer) 
    // 判断状态
    State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    // 这里将LifecycleBoundObserver又进行了一次包装
    ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
    // 然后保存到map中
    ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

    if (previous != null) 
        // 同样的道理,如果缓存存在,直接返回
        return;
    
    // 从WeakReference中获取LifecycleOwner
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
    if (lifecycleOwner == null) 
        // it is null we should be destroyed. Fallback quickly
        return; // 获取不到返回
    

    boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
    State targetState = calculateTargetState(observer);
    mAddingObserverCounter++;
    while ((statefulObserver.mState.compareTo(targetState) < 0
            && mObserverMap.contains(observer))) 
        pushParentState(statefulObserver.mState);
        // 关键代码
        statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
        popParentState();
        // mState / subling may have been changed recalculate
        targetState = calculateTargetState(observer);
    

    if (!isReentrance) 
        // we do sync only on the top level.
        sync();
    
    mAddingObserverCounter--;

分析上面的关键代码,也就是ObserverWithState的dispatchEvent方法

static class ObserverWithState 
    State mState;
    LifecycleEventObserver mLifecycleObserver;

    ObserverWithState(LifecycleObserver observer, State initialState) 
        mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
        mState = initialState;
    

    void dispatchEvent(LifecycleOwner owner, Event event) 
        State newState = getStateAfter(event);
        mState = min(mState, newState);
        // 关键代码,回调LifecycleBoundObserver的onStateChanged方法
        mLifecycleObserver.onStateChanged(owner, event);
        mState = newState;
    

当LifecycleBoundObserver的onStateChanged方法触发后就会触发父类的ObserverWrapper的activeStateChanged方法,activeStateChanged又会触发dispatchingValue方法,而最终会触发considerNotify方法,这个过程熟悉吧,我们上面分析LiveData原理的时候也分析到了,而且重点分析了dispatchingValue方法,当他传入null的时候会分发所有的观察者,当传入具体的ObserverWrapper时就会只会单独回调该ObserverWrapper,这里分析首次注册观察者的时候刚好对应的就是这种情况。

由上面分析得知,但我们首次调用LiveData的observer方法进行观察者注册的时候,其实是会触发LiveData的considerNotify方法触发的,这也就为粘性事件的分发提供了先天条件, 而必要条件就是mVersion > mLastVersion.

4.4 如何避免粘性事件

既然已经知道了原因,那么怎么解决呢? 我这里介绍2种方案:
1、因为每个LiveData都维护了一个mVersion,为了避免影响,我们在注册观察者的时候使用不同的LiveData对象就可以避免相互影响了.
2、自己维护LiveData和mVersion和ObserverWrapper的mLastVersion,这就需要我们重写LiveData了.

这里介绍方式2, 代码如下:

public class BaseLiveData<T> extends MutableLiveData<T> 

    private int mVersion = -以上是关于LiveData的工作原理分析的主要内容,如果未能解决你的问题,请参考以下文章

4. Jetpack源码解析—LiveData的使用及工作原理

4. Jetpack源码解析—LiveData的使用及工作原理

4. Jetpack源码解析—LiveData的使用及工作原理

LiveData原理分析

Android LiveData原理分析

Android LiveData实现原理