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

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

作者: 喂_balabala | 来源:发表于2023-08-16 10:41 被阅读0次

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

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/qsmkmdtx.html