livedata原理分析 (解除livedata粘性事件)

先思考几个问题

livedata是怎么做的监听生命周期的 ?
postValue和setValue有什么区别 ?
事件是如何发送和接收的?
livedata粘性事件是什么 ?
livedata的粘性事件是怎样引起的 ?

首先需要知道注册监听和发送事件的几个方法 observe,postvalue,setvalue,我们主要是对这几个方法进行分析

发送事件

livedata发送事件的方法有两种 postValue和setValue
我们先来看setValue

  • 直接调用到了MutableLiveData的setValue,MutableLiveData是LiveData的具体实现类,把Livedata复制的代码隐藏,只暴露用户需要的几个方法
@Override
    public void setValue(T value) {
        super.setValue(value);
    }
  • 调用到了父类的setValue方法,注意 mVersion++ 和 dispatchingValue方法,并且把需要发送的value值保存到了mData中
@MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");		// 确保是在主线程,否则抛出异常
        mVersion++;							// 版本号加1,这里很重要
        mData = value;						// 保存值
        dispatchingValue(null);				// 分发消息(注意这个方法)
    }

setValue看完了,接下来看postValue

@Override
    public void postValue(T value) {
        super.postValue(value);
    }
  • 先通过锁的方式用一个中间变量存储value,然后传递了一个Runnable给ArchTaskExecutor执行器去执行,看mPostValueRunnable具体实现,也很简单,就是把先前存的data取出来,然后调用setValue去发送消息
protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {	 	// 保证线程安全,保存value值
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }


private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    };
  • 我们知道了runable里面其实也是调用了setValue,重点看postToMainThread做了什么。往下找,在子类DefaultTaskExecutor实现了该方法,这里其实是拿到了主线程的handler,然后把之前的runable post出去,这样就实现了切换至线程
@Override
    public void postToMainThread(Runnable runnable) {
        if (mMainHandler == null) {
            synchronized (mLock) {
                if (mMainHandler == null) {
                    mMainHandler = createAsync(Looper.getMainLooper());
                }
            }
        }
        //noinspection ConstantConditions
        mMainHandler.post(runnable);
    }

总结 : postValue其实也是通过的setValue发送消息,不同的是,postValue通过handler进行了线程切换,这样在子线程中发送消息也不会报错,而setValue会直接抛出异常

事件接收

看完了事件的发送,我们来看事件接收,注意到上面发送事件时会调用到dispatchingValue方法,这个很关键

要分析事件的接收,我们首先来看是如何注册监听的

  • 传入了两个参数,生命周期的持有者和一个observer观察回调方法,然后创建了LifecycleBoundObserver对象,将生命周期持有者和observer打包,最后调用addObserver给持有者添加了该对象,这里好像看不出如何接收value的,我们点进去看LifecycleBoundObserver的具体实现。
  • 这里livedata是被观察者,mObservers是观察者集合,每次调用observe就相当于往mObservers集合中添加了一个观察者,代码中表现为mObservers.putOfAbsent
@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);
    }
  • 非常高兴的找到了onStateChanged方法,这不就是lifecycle的状态回调方法吗,当生命周期状态发生改变,变成活跃状态时会调用到activeStateChanged
@Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            if (currentState == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            Lifecycle.State prevState = null;
            while (prevState != currentState) {
                prevState = currentState;
                activeStateChanged(shouldBeActive());
                currentState = mOwner.getLifecycle().getCurrentState();
            }
        }
  • 再次判断了当前生命周期状态,如果是活跃状态,看到了我们上面提到的dispatchingValue方法,注意这里传的是this,而之前的setValue传的是null
void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            changeActiveCounter(mActive ? 1 : -1);
            if (mActive) {
                dispatchingValue(this);
            }
        }
  • 下面的if else分别对应了生命周期状态改变流程和事件接收流程,看两个流程的区别,事件接收时会遍历mObservers整个观察者列表,然后调用considerNotify,再来看看considerNotify做了什么
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;
    }
  • 上面的一些检查代码不管,看最下面几行,先判断当前观察者的版本和livedata的版本,然后将两个版本进行同步,最后调用我们之前写的observer回调,mData就是我们之前setValue的时候存的值,至此接收事件完成
  • mLastVersion 和 mVersion分别用于标识最后一次observe进行回调的版本和livedata最后一次发送数据的版本,初始值均为-1,每次发送数据mVersion++,每次接收数据同步mLastVersion和mVersion
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);
    }
粘性事件是什么

所谓的粘性是数据发送早于注册监听,当我们进行注册observe时,回调了上一次的老数据,从代码的层面来看,先调用了setValue将mVersion进行++,然后注册监听,当生命周期活跃时,会调用到considerNotify,而此时的mLastVersion时初始值-1,if条件不成立,进而调用onChanged接收了上一次数据

这里得满足两个条件会触发粘性事件
1.数据发送早于注册监听
2.监听者的owner生命周期进入活跃状态

livedata是被观察者,mObservers是观察者集合
要注意,mVersion存放在livedata中,而mLastVersion存放在livedata的被观察者中

如何解除粘性事件

从源码里分析很容易知道。我们只需要修改mLastVersion值,使得第一次的if条件成立就OK,具体的实现就是通过反射,找到ObserverWrapper修改它的mLastVersion的值
具体实现代码

  • 在注册监听之后调用该hook方法即可
private fun hook(observer: Observer<*>) {
            runCatching {
                val liveDataClazz = LiveData::class.java
                val mapClazz = SafeIterableMap::class.java
                val getMethod: Method = mapClazz.getDeclaredMethod("get", Any::class.java)
                getMethod.isAccessible = true
                val observerField = liveDataClazz.getDeclaredField("mObservers")
                observerField.isAccessible = true

                val observers = observerField.get(this)
                val invokeEntry = getMethod.invoke(observers, observer)
                var boundObserver: Any? = null
                if (invokeEntry != null && invokeEntry is Map.Entry<*, *>) {
                    boundObserver = invokeEntry.value
                }
                if (boundObserver == null) {
                    throw NullPointerException("boundObserver 为空")
                }

                val observerWrapperClazz: Class<*> = boundObserver.javaClass.superclass
                val mLastVersionField: Field = observerWrapperClazz.getDeclaredField("mLastVersion")
                mLastVersionField.isAccessible = true
                val mVersionField: Field = liveDataClazz.getDeclaredField("mVersion")
                mVersionField.isAccessible = true
                val mVersionValue: Any = mVersionField.get(this)!!
                mLastVersionField.set(boundObserver, mVersionValue)
            }.onFailure {
                it.printStackTrace()
            }
        }
最后放一个事件总线的Livedata封装代码
object LiveDataBus {

    private val busMap: MutableMap<String, BusMutableLivedata<Any>> by lazy { HashMap() }

    @Suppress("UNCHECKED_CAST")
    @Synchronized
    fun <T> with(key: String, type: Class<T>, isStick: Boolean = false): BusMutableLivedata<T> {
        if (!busMap.containsKey(key)) {
            busMap[key] = BusMutableLivedata(isStick)
        }
        (busMap[key] as BusMutableLivedata<T>).isStick = isStick
        return busMap[key] as BusMutableLivedata<T>
    }

    class BusMutableLivedata<T> private constructor() : MutableLiveData<T>() {
         var isStick: Boolean = false            // 默认取消粘性事件

        constructor(isStick: Boolean) : this() {
            this.isStick = isStick
        }

        override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
            super.observe(owner, observer)

            if (!isStick) {
                hook(observer)
            }
        }

        private fun hook(observer: Observer<*>) {
            runCatching {
                val liveDataClazz = LiveData::class.java
                val mapClazz = SafeIterableMap::class.java
                val getMethod: Method = mapClazz.getDeclaredMethod("get", Any::class.java)
                getMethod.isAccessible = true
                val observerField = liveDataClazz.getDeclaredField("mObservers")
                observerField.isAccessible = true

                val observers = observerField.get(this)
                val invokeEntry = getMethod.invoke(observers, observer)
                var boundObserver: Any? = null
                if (invokeEntry != null && invokeEntry is Map.Entry<*, *>) {
                    boundObserver = invokeEntry.value
                }
                if (boundObserver == null) {
                    throw NullPointerException("boundObserver 为空")
                }

                val observerWrapperClazz: Class<*> = boundObserver.javaClass.superclass as Class<*>
                val mLastVersionField: Field = observerWrapperClazz.getDeclaredField("mLastVersion")
                mLastVersionField.isAccessible = true
                val mVersionField: Field = liveDataClazz.getDeclaredField("mVersion")
                mVersionField.isAccessible = true
                val mVersionValue: Any = mVersionField.get(this)!!
                mLastVersionField.set(boundObserver, mVersionValue)
            }.onFailure {
                it.printStackTrace()
            }
        }
    }
}

你可能感兴趣的:(Android,Jetpack,flutter,kotlin,android)