Andorid-JetPack-LiveData组件用法和源码解析

本文目标

理解并掌握LiveData组件用法和原理

1.什么是LiveData

  • LiveData组件是Jetpack推出的基于观察者的消息订阅/分发组件,具有宿主(Activity,Fragment)生命周期感知能力,这种感知能力可确保LiveData仅分发消息给处于活跃状态的观察者,即只有处于活跃状态的观察者才能收到消息
  • LiveData的消息分发机制,是以往的Handler,EventBus,RxjavaBus无法比拟的,他们不会顾及到当前页面是否可见,一股脑的有消息就发送.导致即便应用在后台,页面不可见,还在做一些无用的绘制,细心的小伙伴可以发现微信消息列表是在可见状态时才会更新列表最新消息的

活跃状态:Observer所在宿主处于STARTED,RESUMED状态

2.基本用法

  • MutableLiveData
    我们在使用LiveData的做消息分发的时候,需要使用到这个子类.其实MutableLiveData只是继承了LiveData,然后重写了postValue(T)setValue(T),把父类的protected改成了public,之所以这么设计,是考虑到单一开闭原则,只有拿到MutableLiveData对象才可以发送消息,LiveData对象只能接受消息,避免拿到LiveData对象时既能发消息也能收消息的混乱使用.
public class MutableLiveData<T> extends LiveData<T> {

    /**
     * Creates a MutableLiveData initialized with the given {@code value}.
     *
     * @param value initial value
     */
    public MutableLiveData(T value) {
        super(value);
    }

    /**
     * Creates a MutableLiveData with no value assigned to it.
     */
    public MutableLiveData() {
        super();
    }

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

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}
  • MediatorLiveData
    1.可以统一观察多个LiveData的发射的数据进行统一处理
    2.同时也可以作为一个LiveData,被其他Observer观察
//创建两个长的差不多的LiveData对象
MutableLiveData<String> liveDat1=new MutableLiveData<>();
MutableLiveData<String> liveDat2=new MutableLiveData<>();

//在创建一个聚合类MediatorLiveData
MediatorLiveData<String> allLiveData=new MediatorLiveData<>();

//可以观察到
Observer<String> observer = new Observer<String>() {
      @Override
     public void onChanged(String s) {
        Log.i("yd","onChanged刷新一次");
    }
};
//分别把上面创建的两个LiveData对象添加进来
allLiveData.addSource(liveDat1,observer );
allLiveData.addSource(liveDat2,observer );

//一旦liveDat1或liveDat2发送了新的数据,observer便可以观察到,以便统一处理更新UI

3.黏性消息实现原理

  • 黏性消息分发流程,即新注册的Observer也能接受到前面发送的最后一条数据,通俗来说就是先发射事件,然后在注册观察者,照样能收到

我们从LiveDatapublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)方法看起,来直接上源码

public abstract class LiveData<T> {
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        //1,把observer包装成 LifecycleBoundObserver
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        //存到map集合中,有消息就去分发
        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;
        }
        //3.把上面包装后的对象 注册到 `Lifecycle`之中
        owner.getLifecycle().addObserver(wrapper);
    }
}

该方法主要做了两件事

  • 1.把observer包装成 LifecycleBoundObserver具有生命周期边界的观察者,也就是说宿主状态是STARTEDRESUMED才会接受数据,其他状态不接受数据
  • 2.存到map集合中,有消息就去分发,key:我们传进来的Observer对象,value:包装成的LifecycleBoundObserver对象
  • 3.把上面包装后的对象 注册到 Lifecycle之中,这里就是LiveData利用Lifecycle的地方,能感知生命周期的关键地方,初次注册,宿主每次生命周期的变化都会回调onStateChanged方法,也就是说会回调LifecycleBoundObserveronStateChanged()方法,
    来我们看下LifecycleBoundObserver
public abstract class LiveData<T> {

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

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

        //宿主的状态是否处于活跃状态,其实就是判断宿主是否是STARTED或RESUMED
        @Override
        boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            //1.宿主被销毁事件,则从liveData移除该观察者,流程结束
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            //2.如果宿主的状态为活跃状态STARTED,RESUMED,则分发最新数据到每个观察者
            activeStateChanged(shouldBeActive());
        }

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

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

onStateChanged(Event event)方法中,

  • 1.宿主被销毁事件,则从liveData移除该观察者,流程结束
  • 2.activeStateChanged(shouldBeActive());这行代码,如果宿主的状态是活跃的为STARTED,RESUMED,则分发最新数据到每个观察者,
    具体是如何进行的我们可以追进去看下
public abstract class LiveData<T> {

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

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

        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            mActive = newActive;
            //没有任何一个观察者处于活跃状态
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
           //1.当且仅当有一个观察者的时候才会触发
            if (wasInactive && mActive) {
                onActive();
            }
           //2.如果没有任何一个活跃的观察者,则会触发
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            //3.如果宿主的状态是活跃的为STARTED,RESUMED,则分发最新数据到每个观察者,
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }
}
  • 1.做一些判断,当且仅当有一个观察者的时候才会触发onActive()方法,该方法是空方法(官方留给我们的口子)
  • 2.如果没有任何一个活跃的观察者,则会触发onInactive();方法,该方法是空方法(官方留给我们的口子)
  • 3.如果宿主的状态是活跃的为STARTED,RESUMED,则分发最新数据到每个观察者,触发dispatchingValue(this);
    继续往下追
public abstract class LiveData<T> {

    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            //如果传入的对象不为空,则直接调用分发事件方法
            if (initiator != null) {
                considerNotify(initiator);
                initiator = null;
            } else {
                //为空,说明是从 setValue方法进来,的需要for循环遍历一遍,然后把事件分发给观察者
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    //该行代码中真正的分发了事件
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }
}
  • 1.如果传入的对象initiator不为空,则直接调用分发事件方法
  • 2.如果传入的对象initiator为空,说明是从 setValue方法进来,的需要for循环遍历一遍,然后把事件分发给观察者
    不论对象initiator是否为空,最后都会调用considerNotify(iterator.next().getValue());
    这行代码才是真正的去分发事件
public abstract class LiveData<T> {
    private void considerNotify(ObserverWrapper observer) {
        //1.如果观察者所在的宿主不活跃了,不分发
        if (!observer.mActive) {
            return;
        }
        //判断观察者是否处于活跃状态
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        //2.如果observer.mLastVersion >= LiveData的mVersion,不分发
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //3.分发数据
        observer.mObserver.onChanged((T) mData);
    }
}

上面的considerNotify(ObserverWrapper observer)方法里面会做一些判断

  • 1.如果观察者所在的宿主不活跃了,不分发
  • 2.如果observer.mLastVersion >= LiveData的mVersion不分发,最初 observer.mLastVersion初始化值为-1,然后LiveDatamVersion在创建之初也等于-1,如果LiveData发送过数据了,这个mVersion就不等于-1了,每次setValue(T value)的时候都会mVersion++,所以第一次注册数据的时候,
    observer.mLastVersion = -1 , mVersion=0,-1 >= 0么?显然条件不满足,然后就会执行下面的数据分发,就会出现黏性事件
  • 3.分发数据
4.普通消息分发流程
  • 即调用postValue,setValue才会触发消息的分发


来直接上源码,先看postValue(T value)

public abstract class LiveData<T> {
    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);
        }
    };

    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            //1.先把消息保存成成员变量mPendingData
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        //2.用handler把消息发送到主线程中
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
}

该方法可以用在子线程,所以这里会使用handler.post先发送到主线程,在分发消息

  • 1.先把消息保存成成员变量mPendingData
  • 2.用handler把消息发送到主线程中
  • 3.在Runnable中,直接调用setValue((T) newValue);
    接下来看下setValue(T value)
    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

mVersion++记录当前发送的消息的次数,用于和observerversion作对比,防止消息重复,
接下来看dispatchingValue(@Nullable ObserverWrapper initiator),流程就和分析黏性事件的后面流程一样了,最后会调用considerNotify(iterator.next().getValue());经过一系列判断,真正的把事件发送出去

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

推荐阅读更多精彩内容