LiveData源码学习笔记

在之前学习MVVM的搭建的时候涉及到了LiveData这个可被观察的数据持有类,在ViewModel中使用LiveData封装数据确实能够为开发者提供了更高效的更新UI的方式。

LiveData最显著的两个特点:

  • 基于观察者模式
  • 同组件的生命周期绑定,能够及时的意识到组件的生命周期

关于结合LiveData搭建MVVM的方法移步这里

一. LiveData和MutableLiveData

MutableLiveData是LiveData的子类,MutableLiveData对外提供了两个方法:

    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
    

postValue和setValue是LiveData提供的两种改变数据的方法,它们在LiveData中都是protected的,如果我们需要手动的设置数据,则需要将数据封装在MutableLiveData中。

在官方的文档中告诉我们postValue和setValue的区别在于:

  • postValue():可以在主线程或者子线程调用,postValue会将任务发布到主线程以设置给定值。

源码如下:

    protected void postValue(T value) {
        boolean postTask;
        //支持子线程中更新给定值的原因
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        //切换到主线程去执行任务
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

在postValue中给Object mDataLock加了锁,这样能够防止多个子线程对mDataLock进行操作,同时如果在主线程执行已发布任务之前多次调用此方法,则只发送最后一个值。这也是频繁调用postValue更新数据有可能会丢失数据的原因。

再看切换到主线程的Runnable:

    private final Runnable mPostValueRunnable = new Runnable() {
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            //noinspection unchecked
            setValue((T) newValue);
        }
    };

可以看到,其实在postValue中最后还是通过setValue来设置给定值。

  • setValue():只能在主线程设置给定值,如果不在主线程调用setValue,会抛出异常。

源码如下:

    @MainThread
    protected void setValue(T value) {
        //判断当前是否在主线程
        assertMainThread("setValue");
        
        mVersion++;
        mData = value;
        
        //分发给定值通知更新
        dispatchingValue(null);
    }

二.添加观察者

LiveData中为我们提供了两个添加观察者的方法,observe()和observeForever()。从源码来看看这两个方法之间有何不同。

  • observe():
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // 如果组件处于未激活状态,则不做任何处理
            return;
        }
        //将owner和observer对象封装成新的观察者对象
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        //如果mObservers中已经存在观察者和wrapper的关联则返回,如果不存在,则关联并且返回null
        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;
        }
        //添加Lifecycle的观察者
        owner.getLifecycle().addObserver(wrapper);
    }

首先能够看出来,observe()也是必须在主线程中执行的。并且在observe中,observe是否执行是和组件的生命状态息息相关的。

observe里将onwer和observer封装成了一个新的观察者添加给Lifecycle,具体的逻辑在代码注释中已经写出,不做赘述。

  • observeForever():
    @MainThread
    public void observeForever(@NonNull Observer<T> observer) {
        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;
        }
        //将活动状态设置为true保证无论如何都能通知数据的变更
        wrapper.activeStateChanged(true);
    }

从方法命名和代码能够看得出来,observeForever()和observe()最大的不同点就是observeForever不受组件的生命周期的限制,即使组件处于未激活状态,使用observeForever注册的观察者依旧会收到数据变化的通知。

从observeForever的参数列表和AlwaysActiveObserver的构造函数中也能够看出来,wrapper并没有将owner传入,所以观察者并不受组件生命周期的影响。

需要注意:由于使用observeForever()方法注册的观察者并不受组件生命周期的影响,所以不再需要使用观察者的时候需要手动的调用removeObserver()方法移除观察者。

三. dispatchingValue()数据变化消息的调度方法

之前在setValue()方法中,最后通过dispatchingValue()方法来通知观察者消息的变化,结合源码看看dispatchingValue究竟是怎么做到的。

    private void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

在setValue时,通过dispatchingValue(null)来实现数据变化的通知,从代码可以看出来,这个通知是通知mObservers容器中的对象,这个通知具体在considerNotify的方法里:

    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);
   }

considerNotify方法首先会对当前组件的状态是否为最新状态进行判断,如果不是最新的状态,则不做任何处理,这样做是为了预防组件状态更新但没有收到事件的不稳定事件导致可能会发生无法预测的后续事件。

在看observer.mObserver.onChanged((T) mData);这句代码才是这个方法最主要的任务——通知观察者数据的变化。这里的onChanged其实就是重写的onChanged()方法。

结合之前写的MVVM的Demo来看看,整体的一个流程吧~(以refresh为例,为什么只需要设置一个isRefresh就能够直接更新User的信息), 看图说话~

refresh实现流程

四. LiveData与组件的生命周期

LiveData同组件的生命周期绑定,能够及时的意识到组件的生命周期是LiveData的一大特点,在组件未激活的状态下LiveData不会将数据的改变通知给观察者,在组件DESTORY后LiveData会自动的清除观察者,在LiveData中肩负这个使命的是LifecycleBoundObserver,源码走起~

先看LifecycleBoundObserver的继承关系:

class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver

ObserverWrapper在observeForever()中已经出现过了,LifecycleBoundObserver作为ObserverWrapper的子类,个性的部分就是对组件生命周期的监听。

GenericLifecycleObserver是一个继承自LifecycleObserver的接口(LifecycleObserver只是一个样本,并没有声明任何方法),GenericLifecycleObserver中声明了一个onStateChanged()方法,用于接收组件任何生命周期的更改并且发送给接收的一方。

再看看LifecycleBoundObserver的构造函数:

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

构造函数传入了一个LifecycleOwner,这个owner就是继承自LifecycleOwner的组件,通过owner可以获取到组件的状态。

接下来看看onStateChanged()方法的具体实现:

        @Override
       public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
           //DESTROYED状态移除观察者
           if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
               removeObserver(mObserver);
               return;
           }
           //判断状态
           activeStateChanged(shouldBeActive());
       }

从代码中可以了解到,onStateChanged主要工作就是感知到组件状态的变化,最后将这个状态交给activeStateChanged处理(DESTROYED除外),再看看activeStateChanged的源码:

        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) {
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            if (mActive) {
                dispatchingValue(this);//任务处理,分发
            }
        }

在activeStateChanged中首先对新状态进行了判断以避免重复处理,之后将组件状态更新到最新。

mActiveCount用来记录组件存活的数量,这是因为同一个ViewModel可以被多个组件绑定。如果有存活的组件则调用onActive(),没有则调用onInactive(),这两个方法都是空方法,可以根据实际需求继承LiveData自己实现。

最后如果组件是存活状态,则通过调用dispatchingValue()进行事件分发。

五.总结

到这里LiveData的源码学习暂时告一段落,LiveData应用观察者模式保证了数据和UI的分离,是在学习观察者模式上实际应用中一个较好的参考例子。

相关笔记传送门:
MVVM设计模式学习笔记(一)——MVVM初体验
MVVM设计模式学习笔记(二)——结合LiveData来搭建MVVM

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容