【安卓笔记】解决livedata粘性事件

发布于:2025-07-25 ⋅ 阅读:(18) ⋅ 点赞:(0)

0. 前言

关于livedata,可以看我之前写的文章:【安卓笔记】lifecycle与viewModel-CSDN博客

livedata粘性事件是指:先postValue(),后observe(),会导致observe也能收到第一次post的值的问题 

1. 先看源码

我们要如何实现,解决粘性事件的问题?

我们通过源码发现:

public abstract class LiveData<T> {
    ·
    ·
    ·
    @SuppressWarnings("unchecked")
    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);
    }
    ·
    ·
    ·
}

 其中有一段

        if (observer.mLastVersion >= mVersion) {
            return;
        }

于是就有思路,使mLastVersion >= mVersion 就可以return了

2. 思路: mLastVersion >= mVersion

为了使mLastVersion >= mVersion,我们需要重写LiveData中的方法。因此用到hook。(想了解hook可以通过我的这篇文章:【安卓笔记】RxJava的Hook机制,整体拦截器-CSDN博客,虽然说得是RxJava的hook,但是大差不差)

3. 正式开工

这边贴出重写的LiveData代码:

public static class BusMutableLiveData<T> extends MutableLiveData {
    @Override
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
        super.observe(owner, observer);
        hook(observer);
    }

    private void hook(Observer<? super T> observer) {
        //通过反射,来修改mVersion
        /**
         * 思路是:使mLastVersion == mVersion (mLastVersion: {@link LiveData.ObserverWrapper.mLastVersion}; mVersion: {@link LiveData.mVersion})
         * 详见:{@link LiveData#considerNotify}
         * 让下面的代码return就行
         *      if (observer.mLastVersion >= mVersion) {
         *          return;
         *      }
         * 具体操作步骤:
         * 1. 获取 mLastVersion :livedata --> mObservers --> mObservers.get() --> ObserverWrapper --> mLastVersion
         * 2. 获取 mVersion :livedata --> mVersion
         * 3. 使 mLastVersion = mVersion
         */
        try {
            // 1. 获取mLastVersion
            // 获取到livedata类
            Class<LiveData> liveDataClass = LiveData.class;
            // 获取类中,成员名为mObserver的对象:SafeIterableMap
            Field mObserverField = liveDataClass.getDeclaredField("mObservers");
            // 设置成可修改
            mObserverField.setAccessible(true);
            // 获取到这个成员变量的对象
            Object mObserverObject = mObserverField.get(this);
            // 得到map对象的class对象:SafeIterableMap.class
            Class<? extends Field> mObserversClass = mObserverField.getClass();
            // 获取到 mObserversClass 的get方法
            Method get = mObserversClass.getDeclaredMethod("get", Object.class);
            get.setAccessible(true);
            // 执行get方法
            Object invokeEntry = get.invoke(mObserverObject, observer);
            // 取到invokeEntry中的value
            Object observerWrapper = null;
            if (invokeEntry != null && invokeEntry instanceof Map.Entry) {
                observerWrapper = ((Map.Entry<?, ?>) invokeEntry).getValue();
            }
            // 判空
            if (observerWrapper == null) {
                throw new NullPointerException("observerWrapper is null");
            }
            // 得到observerWrapper的类对象
            Class<?> superclass = observerWrapper.getClass().getSuperclass();
            // 获取名为mLastVersion的成员对象
            Field mLastVersion = superclass.getDeclaredField("mLastVersion");
            mLastVersion.setAccessible(true);
            // 2. 获取mVersion
            Field mVersion = liveDataClass.getDeclaredField("mVersion");
            mVersion.setAccessible(true);
            // 3. 使mLastVersion = mVersion
            Object mVersionValue = mVersion.get(this);
            mLastVersion.set(observerWrapper, mVersionValue);

        } catch (Exception e) {

        }
    }
}

4. 如何使用

具体使用方式,可以查看我的这篇文章:【安卓笔记】lifecycle与viewModel-CSDN博客

其中 3. livedata的使用,有介绍如何使用。

修改了LiveDataBus的代码,我贴在这边:

public class LiveDataBusX {
    private Map<String, BusMutableLiveData<Object>> bus;   // hashMap用于存放订阅者

    private static LiveDataBusX liveDataBus = new LiveDataBusX();

    public LiveDataBusX() {
        bus = new HashMap<>();
    }

    public static LiveDataBusX getInstance() {
        return liveDataBus;
    }

    /**
     * 注册订阅者
     */
    public synchronized <T> BusMutableLiveData<T> with(String key, Class<T> type) {
        if (!bus.containsKey(key)) {
            bus.put(key, new BusMutableLiveData<Object>());
        }
        return (BusMutableLiveData<T>) bus.get(key);
    }

    public static class BusMutableLiveData<T> extends MutableLiveData {
        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
            super.observe(owner, observer);
            hook(observer);
        }

        private void hook(Observer<? super T> observer) {
            //通过反射,来修改mVersion
            /**
             * 思路是:使mLastVersion == mVersion (mLastVersion: {@link LiveData.ObserverWrapper.mLastVersion}; mVersion: {@link LiveData.mVersion})
             * 详见:{@link LiveData#considerNotify}
             * 让下面的代码return就行
             *      if (observer.mLastVersion >= mVersion) {
             *          return;
             *      }
             * 具体操作步骤:
             * 1. 获取 mLastVersion :livedata --> mObservers --> mObservers.get() --> ObserverWrapper --> mLastVersion
             * 2. 获取 mVersion :livedata --> mVersion
             * 3. 使 mLastVersion = mVersion
             */
            try {
                // 1. 获取mLastVersion
                // 获取到livedata类
                Class<LiveData> liveDataClass = LiveData.class;
                // 获取类中,成员名为mObserver的对象:SafeIterableMap
                Field mObserverField = liveDataClass.getDeclaredField("mObservers");
                // 设置成可修改
                mObserverField.setAccessible(true);
                // 获取到这个成员变量的对象
                Object mObserverObject = mObserverField.get(this);
                // 得到map对象的class对象:SafeIterableMap.class
                Class<? extends Field> mObserversClass = mObserverField.getClass();
                // 获取到 mObserversClass 的get方法
                Method get = mObserversClass.getDeclaredMethod("get", Object.class);
                get.setAccessible(true);
                // 执行get方法
                Object invokeEntry = get.invoke(mObserverObject, observer);
                // 取到invokeEntry中的value
                Object observerWrapper = null;
                if (invokeEntry != null && invokeEntry instanceof Map.Entry) {
                    observerWrapper = ((Map.Entry<?, ?>) invokeEntry).getValue();
                }
                // 判空
                if (observerWrapper == null) {
                    throw new NullPointerException("observerWrapper is null");
                }
                // 得到observerWrapper的类对象
                Class<?> superclass = observerWrapper.getClass().getSuperclass();
                // 获取名为mLastVersion的成员对象
                Field mLastVersion = superclass.getDeclaredField("mLastVersion");
                mLastVersion.setAccessible(true);
                // 2. 获取mVersion
                Field mVersion = liveDataClass.getDeclaredField("mVersion");
                mVersion.setAccessible(true);
                // 3. 使mLastVersion = mVersion
                Object mVersionValue = mVersion.get(this);
                mLastVersion.set(observerWrapper, mVersionValue);

            } catch (Exception e) {

            }
        }
    }
}

5. 写在最后

通过反射修改LiveData,这样我们就解决了粘性事件。可以忽略第一次postValue的问题


网站公告

今日签到

点亮在社区的每一天
去签到