LiveData原理、源码分析-粘性事件(数据倒灌)分析及解决

《Lifecycle原理、源码解析》
《LiveData简介及使用-什么是LiveData的粘性事件(数据倒灌)?》

  • 查看LiveData的observe可知是如何绑定的
    @MainThread
    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);
    }
  • owner就是activity。这个函数就可看出已经绑定上了
  • 里面有个关键函数是LifecycleBoundObserver的创建
  • LifecycleBoundObserver是ObserverWrapper的子类
  • ObserverWrapper有个activeStateChanged函数很关键,下面还会提到
  • 记住activeStateChanged里也调用了dispatchingValue
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);
    }
}
  • 再看owner.getLifecycle().addObserver(wrapper)
  • 实现是在LifecycleRegister里的addObserver函数
  • 里面调用了calculateTargetState,去计算当前生命周期的状态,状态更新了就会触发ObserverWrapper里面的activeStateChanged
  • 这样就又执行了activeStateChanged里面的dispatchingValue函数
  • 这里也是LiveData粘性事件的根源
    @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

        if (previous != null) {
            return;
        }
        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--;
    }
  • 再看LiveData类中的postValue函数
protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
  • postToMainThread看名字也可知post最终是传到主线程调用
private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    };
  • 再看mPostValueRunnable可知postValue最终也是调用的setValue
  • 关键函数在setValue -> dispatchingValue -> considerNotify
  • 由此代码顺序可看出最终就在considerNotify里调用onChanged来完成通知的
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

...
...

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<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

...
...

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()) {
        observer.activeStateChanged(false);
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);
}

  • setValue里面有一个mVersion,每次数据变化就加加
  • considerNotify先判断当前activity是否可见,然后再判断是否还没来得及更新activity的可见状态。此知识点需先了解lifecycle
  • considerNotify里面会判断mLastVersion和mVersion的值。版本不一致才会往下走,通知最新的数据变化

static final int START_VERSION = -1;

public LiveData(T value) {
    mData = value;
    mVersion = START_VERSION + 1;
}

/**
 * Creates a LiveData with no value assigned to it.
 */
public LiveData() {
    mData = NOT_SET;
    mVersion = START_VERSION;
}
  • 查看LiveData的构造函数可知,一般我们使用的是空参构造,所以mVersion的初始值是-1

为什么会有粘性事件?

原因:执行顺序变了
  • 原来的执行顺序new LiveData-->绑定observer-->setValue执行onChanged
  • 而我们的BUS在用时可能出现 new LiveData-->setValue执行onChanged-->绑定observer
  • 通过setValue函数可知只要调用一次,mVersion就加一,activity还没创建,也就是还没绑定observer的时候也加一了。
  • setValue会调用dispatchingValue(null),参数是null,会走里面的for循环,此时是没什么影响,因为mObservers找不到还没绑定的activity。
  • 但是假如setValue发送了10次,此时mVersion就已经是10了
  • 然后activity再创建,再绑定observer的时候,查看LiveData的observe函数,再查看里面的关键函数LifecycleBoundObserver的创建
  • LifecycleBoundObserver是ObserverWrapper的子类
  • ObserverWrapper有个activeStateChanged函数
  • activeStateChanged里也调用了dispatchingValue
  • 因为在绑定的时候就会监听生命周期变化,状态变了就触发状态更新
  • 又会执行considerNotify,此时mVersion已经是10了,但是mLastVersion还是-1,所以就往下走,就收到了旧数据的通知
处理方案: 让第一次setValue不起效即可
  • 自定义MutableLiveData,重写observe,反射修改mLastVersion的值,让它跟mVersion相等
package com.example.livedatabus;


import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData;
import android.arch.lifecycle.Observer;
import android.support.annotation.NonNull;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


public class LiveDataBus {

    private static volatile LiveDataBus liveDataBus = null;
    private Map<String, BalaLiveDataBus<Object>> map = null;

    private LiveDataBus() {
        map = new HashMap<>();
    }

    public static LiveDataBus getLiveDataBus() {
        if (liveDataBus == null) liveDataBus = new LiveDataBus();
        return liveDataBus;
    }

    public void removeData(String... keys){
        for (String key : keys) {
            map.remove(key);
        }
    }

    public synchronized <T> BalaLiveDataBus<T> with(String str, Class<T> objectClass) {

        if (!map.containsKey(str)) {
            map.put(str, new BalaLiveDataBus<Object>());
        }
        return (BalaLiveDataBus<T>) map.get(str);
    }

    /**
     * 为了不执行 MutableLiveData 中Observer的onChange方法  观察源码如下:
     * <p>
     * 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()) {
     * observer.activeStateChanged(false);
     * return;
     * }
     * if (observer.mLastVersion >= mVersion) {
     * return;
     * }
     * observer.mLastVersion = mVersion;
     * //noinspection unchecked
     * observer.mObserver.onChanged((T) mData);
     * <p>
     * 思路:让 observer.mLastVersion == mVersion (此修改不会改动到源码本来的逻辑)
     * <p>
     * 观察源码发现:
     * mVersion 是 LiveData的成员变量
     * observer.mLastVersion 的 observer 是 ObserverWrapper对象
     * ObserverWrapper 是 Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator中的value
     * iterator 相当于是 LiveData 中的成员变量 SafeIterableMap<Observer<T>, ObserverWrapper> mObservers
     *
     * @param <T>
     */
    public static class BalaLiveDataBus<T> extends MutableLiveData<T> {

        private boolean mIsViscidity = true;

        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer, boolean isViscidity) {
            mIsViscidity = isViscidity;
            observe(owner, observer);
        }

        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
            super.observe(owner, observer);
            if (mIsViscidity) return;
            try {
                Class<LiveData> liveDataClass = LiveData.class;
                //获取到mObservers对象
                Field mObserversField = liveDataClass.getDeclaredField("mObservers");
                mObserversField.setAccessible(true);
                //从当前的livedata对象中获取mObservers在当前成员变量中的值
                Object mObservers = mObserversField.get(this);
                //获取到mObservers的类型 SafeIterableMap
                Class<?> mObserversClass = mObservers.getClass();
                //获取到SafeIterableMap的get方法
                //get参数是一个泛型 但是又要传class对象  所以传object的
                Method get = mObserversClass.getDeclaredMethod("get", Object.class);
                get.setAccessible(true);
                //要执行mObservers的get方法  参数是observer
                //此时的对象就是 Entry<K, V>
                Object invokeEntry = get.invoke(mObservers, observer);
                Object observerWrapper = null;
                if (invokeEntry != null && invokeEntry instanceof Map.Entry) {
                    observerWrapper = ((Map.Entry) invokeEntry).getValue();
                }
                if (observerWrapper == null) {
                    throw new NullPointerException("observerWrapper==null");
                }
                /*
                 *为什么要获取父类对象?因为在LiveData的observe中new的是ObserverWrapper的子类
                 * LifecycleBoundObserver,但是要找的mLastVersion在ObserverWrapper中
                 */
                Class<?> superclassWrapper = observerWrapper.getClass().getSuperclass();
                Field mLastVersion = superclassWrapper.getDeclaredField("mLastVersion");
                mLastVersion.setAccessible(true);
                Field mVersion = liveDataClass.getDeclaredField("mVersion");
                mVersion.setAccessible(true);
                //从当前的livedata对象中获取mVersion的值
                Object o = mVersion.get(this);
                //mVersion的值给mLastVersion  mLastVersion是在observerWrapper里面的
                mLastVersion.set(observerWrapper, o);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

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

推荐阅读更多精彩内容