LiveData 使用与源码分析——完全搞懂LiveData原理

一、LiveData简介

LiveData是google官方架构JetPack系列的一个响应式开发框架,LiveData是一个可以被观察的数据持有者类。说到响应式开发或者说观察者就不免想到RxJava,RxJava将观察者模式运用的炉火纯青。但LiveData和RxJava的定位是不一样的,LiveData主要用于搭建MVVM架构,并在其中作为数据持有者,LiveData能监听组件的生命周期变化,这样一来只会更新处于活跃状态的组件。

LiveData的特点:
1)采用观察者模式,数据发生改变,可以自动回调(比如更新UI)。
2)不需要手动处理生命周期,不会因为Activity的销毁重建而丢失数据。
3)不会出现内存泄漏。
4)不需要手动取消订阅,Activity在非活跃状态下(pause、stop、destroy之后)不会收到数据更新信息。

LiveData 的生命周期感知是由Lifecycle来实现的,不了解Lifecycle的可以查看Lifecycle 使用与源码分析——彻底搞懂Lifecycle原理

二、使用方法

在分析源码前,简单的介绍一下LiveData的使用,根据使用来逐一对源码进行分析

可以在viewmodel 中这样使用:

// Declaring it
val liveDataA = MutableLiveData<String>()

// Trigger the value change
liveDataA.value = someValue

可以在fragment 中这样使用:

class MutableLiveDataFragment : Fragment() {

// 当liveDataA 的数据发生变化,就会调用Observer 的onChanged()函数
    private val changeObserver = Observer<String> { value ->
        value?.let { txt_fragment.text = it }
    }

    override fun onAttach(context: Context?) {
        super.onAttach(context)
        getLiveDataA().observe(this, changeObserver)
    }
}

使用非常简单,方便,完全不用考虑更新数据的时候UI的状态

三、源码分析

由于 LiveData 是一个 abstract class,我们不能直接生成他的实例。官方有提供他的实现类MutableLiveData

public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        // LiveData.postValue() 是一个 protected 方法
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        // LiveData.setValue() 是一个 protected 方法
        super.setValue(value);
    }
}

创建了Livedata 后,需要通过observe方法或者observeForever 方法设置一个回调,这个回调接口就是Observer

回调接口

public interface Observer<T> {
    /**
     * Called when the data is changed.
     * @param t  The new data
     */
    void onChanged(@Nullable T t);
}
// 注意,他是 abstract class
public abstract class LiveData<T> {

    ...省略其他代码...
     
    // 只有 onStart 后,对数据的修改才会触发 observer.onChanged()
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {}

    // 无论何时,只要数据发生改变,就会触发 observer.onChanged()
    public void observeForever(@NonNull Observer<T> observer) {}

    ...省略其他代码...
}

observeForever 的实现跟 observe 是类似的,这里我们重点看一下 observe()的实现过程:

    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
		//如当前UI的状态的是DESTROYED,就不绑定这个回调了
        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;
        }
        //把wrapper 与Activity/Fragment的生命周期,建立关系,
        //当UI的生命周期发生变化的时候,就会去回调wrapper中的 onStateChanged
        owner.getLifecycle().addObserver(wrapper);
    }

3.1、生命周期发生变化,LiveData回调接口的调用情况

接下来,我们来看一个当生命周期发生变化的时候,LifecycleBoundObserver 都做了那些操作,熟悉LifeCycle的小伙伴,应该会很熟悉,生命周期发生变化时,会调用onStateChanged

    class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        // 当生命周期发生变化时,会调用这个函数 
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {

           // 当UI的生命周期为DESTROYED,取消对数据变化的监听,移除回调函数
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            //改变数据,传递的参数是shouldBeActive(),它会计算看当前的状态是否是STARTED,也就是 onStart-onPause 期间生命周期
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

我们继续看下activeStateChanged方法是如何对数据进行处理的,它是ObserverWrapper 类中的一个方法,

    private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;

        ObserverWrapper(Observer<? super T> observer) {
            mObserver = observer;
        }

        abstract boolean shouldBeActive();

        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }

        void detachObserver() {
        }

        void activeStateChanged(boolean newActive) {
            // 当前的生命周期和上一次的生命周期状态,是否发生变化,没有发生变化,就直接返回。
            // onStart-onPause 为 true  在这之外的生命周期为false
            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) {
            // 这是一个空函数,可在代码中根据需要进行重写
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
             // 这是一个空函数,可在代码中根据需要进行重写
                onInactive();
            }

			//结合上面的状态判断,我们知道了,生命周期状态从Inactive 到 Active, 就会调用回调函数
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }

为什么在生命周期的活跃状态 从Inactive 到 Active,要去调用livedata设置的回调函数呢?

原因是,在Inactive (在非 onStart-onPause 周期内 )状态,数据发生了变化,然后在回到Active(onStart-onPause 周期内),如果不去调用回调函数,会出现UI的界面,还在显示上一次的数据,所以需要调用回调函数。

再回到代码流程,到了调用dispatchingValue(this);这个函数在数据发生变化,也是会去调用的,所以在后面分析,先来看下,数据发生变化,代码的流程

3.2、LiveData数据发生发生变化,调用回调接口

当数据发生变化,需要调用LiveData的setValue,postValue 方法

从setValue入手,看一下流程

    protected void setValue(T value) {
        assertMainThread("setValue");
        //mVersion 表示数据发生了变化
        mVersion++;
        // 保存了这次变化的数据
        mData = value;
        //分发数据变化,调用回调函数
        dispatchingValue(null);
    }

进入到dispatchingValue方法

该方法中,是通过一个while 循环来通知回调函数,

  1. 如果调用dispatchingValue方法,传入参数,则调用指定的ivedata的回调函数
  2. 如果调用dispatchingValue方法,传入null,则在for循环中,依次通知所有livedata的回调函数
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        //进入while 循环前,设置为true,如果此时另外一个数据发生变化,到了此函数中就直接在上面返回了
        mDispatchingValue = true;
        do {
           //开始for循环前,设置为false,for循环完,也会退出while循环
            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());
                    //这里mDispatchInvalidated 为true,表示在while循环未结束的时候,有其他数据发生变化,并调用了该函数
                    //在上面的if判断中设置了 mDispatchInvalidated = true,
                    // 结束本次for循环,没有退出while循环,开始下一次for循环
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        
        //退出while 后,设置为false,正常处理数据变化
        mDispatchingValue = false;
    }

这里有两个变量

  • mDispatchingValue 这个变量用来控制,是否进入while 循环,以及while 循环 是否已经结束
  • mDispatchInvalidated 这个变量用来控制for 循环是否要重新开始

看下considerNotify 的函数,调用了之前livedata设置的observer的onChanged函数

    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        if (!observer.shouldBeActive()) {
        // 如果当前的生命周期是非活跃,就不回调onChanged函数,
        // 在LifecycleBoundObserver 中记录状态,当生命周期变为活跃,就回去更新数据
            observer.activeStateChanged(false);
            return;
        }
        //数据发生变化了
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);
    }

看完了 setValue,postValue 就很简单了:

    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            // 上一个 post 后还没有执行的 runnable,所以就不需要再 post 了,
            // 但是注意,上面的mPendingData 数据已经是新数据了 
            //用官方的话,就是  If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.
            return;
        }
        // postValue 可以从后台线程调用,因为它会在主线程中执行任务
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

    private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            //这里调用了setValue,和上面分析的流程一样
            setValue((T) newValue);
        }
    };

postValue

至此 Livedata的源码就基本分析完了,希望对你有所帮助

参考:
https://jekton.github.io/2018/07/14/android-arch-LiveData/
https://juejin.im/post/5c8a03065188257ec7053f58

你可能感兴趣的:(Android)