美文网首页
深入理解AAC架构 - LiveDataBus 基于LiveDa

深入理解AAC架构 - LiveDataBus 基于LiveDa

作者: 七零八落问号 | 来源:发表于2020-02-25 01:59 被阅读0次

    LiveData作为AAC架构的关键模块之一,具有优秀的生命周期感知特性。
    本身采用观察者模式,由于其生命周期感知特性,可以用来实现事件总线。

    本文主要内容:

    • 基本思路:基本的实现思路
    • 粘性事件特性分析:LiveData观察时推最新数据引发的问题
    • 解决思路:解决思路和引入粘性事件

    本文主要采用反射对Version进行管理,使用Class作为消息管理。
    也可以使用其他实现方案,或在参考后自建方案:

    本文源码直接拷贝即可使用。
    也可以前往GitHub仓库查看下载:LiveDataBus (采用反射+包装类的形式)


    基本思路:

    • observe()
      即调用LiveData.observe(),基于LiveData的生命周期特性自动管理观察者。
    • observeForever()
      即调用LiveData.observeForever(),对无法提供LifecycleOwner的观察者进行支持。
    • removeObserver()
      即调用LiveData.removeObserver(),移除对应观察者。
    • postMessage()
      发布任意类型的消息,消息会通知所有关注此类型的观察者。
    object LiveDataBus {
        private val mBus: MutableMap<String, MutableLiveData<*>> = hashMapOf()
    
        fun <T : Any> observe(channelClass: Class<T>, owner: LifecycleOwner, observer: Observer<T>) {
            getChannel(channelClass).observe(owner, observer)
        }
    
        fun <T : Any> observeForever(channelClass: Class<T>, observer: Observer<T>) {
            getChannel(channelClass).observeForever(observer)
        }
    
        fun <T : Any> removeObserver(channelClass: Class<T>, observer: Observer<T>) {
            getChannel(channelClass).removeObserver(observer)
        }
    
        fun <T : Any> postMessage(message: T) {
            getChannel(message::class.java as Class<T>).postValue(message)
        }
    
        private fun <T : Any> getChannel(channelClass: Class<T>): MutableLiveData<T> {
            val channelName = channelClass.simpleName
            if (!mBus.containsKey(channelName)) {
                mBus[channelName] = MutableLiveData<T>()
            }
            return mBus[channelName] as MutableLiveData<T>
        }
    }
    

    使用方式:

    // 定义信息
    class Message
    
    // 订阅信息
    LiveDataBus.observe(Message::class.java, mAnyLifecycleOwner, Observer { })
    LiveDataBus.observeForever(Message::class.java, Observer { })
    
    // 发布信息
    LiveDataBus.postMessage(Message())
    

    粘性事件问题

    网上很多LiveDataBus的实现都有对该问题进行分析,主要源自LiveData的实时通知观察者特性,这个原来相当优秀的机制,在用来实现LiveDataBus的时候,反而会引发观察时收到旧消息的问题。

    解决方法并不复杂,通过自定义BusLiveData继承MutableLiveData,并重写observe()observeForever()

    • observe()
      用于通过observe()加入的observer,通过反射,使ObserverWrapper维护的数据版本等于当前LiveData数据版本。
      在触发生命周期回调时,由于数据版本相同,系统判断为已通知,即不会触发数据更新。
    • observeForever()
      使通过observeForever()新加入的observer,需要屏蔽所有通过observeForever()发起的onChanged()调用。
      通过把传入的observer通过一个自定义的ObserverWrapper装修类,在onChanged()判断当前调用栈是否有observeForever(),存在时则不触发实际的observer.onChanged()

    最终方案

    最后修改后的LiveDataBus

    /**
     * LiveDataBus
     * 基于LiveData实现的事件总线
     */
    object LiveDataBus {
        private val mBus by lazy { mutableMapOf<String, BusLiveData<*>>() }
    
        fun <T : Any> observe(channel: Class<T>, owner: LifecycleOwner, observer: Observer<T>) {
            getChannel(channel).observe(owner, observer)
        }
    
        fun <T : Any> observeSticky(channel: Class<T>, owner: LifecycleOwner, observer: Observer<T>) {
            getChannel(channel).observeStick(owner, observer)
        }
    
        fun <T : Any> observeForever(channel: Class<T>, observer: Observer<T>) {
            getChannel(channel).observeForever(observer)
        }
    
        fun <T : Any> observeStickyForever(channel: Class<T>, observer: Observer<T>) {
            getChannel(channel).observeStickyForever(observer)
        }
    
        fun <T : Any> removeObserver(channelClass: Class<T>, observer: Observer<T>) {
            getChannel(channelClass).removeObserver(observer)
        }
    
        fun <T : Any> postMessage(message: T) {
            getChannel(message::class.java as Class<T>).postValue(message)
        }
    
        private fun <T : Any> getChannel(channelClass: Class<T>): BusLiveData<T> {
            return mBus.getOrPut(channelClass.simpleName) {
                BusLiveData<T>()
            } as BusLiveData<T>
        }
    
        /**
         * 自定义的LiveData
         *
         * 用于通过`observe()`加入的`observer`
         * 通过反射,使`ObserverWrapper`维护的数据版本等于当前`LiveData`数据版本。
         * 在触发生命周期回调时,由于数据版本相同,系统判断为已通知,即不会触发数据更新。
         *
         * 使通过`observeForever()`新加入的`observer`
         * 需要屏蔽所有通过`observeForever()`发起的`onChanged()`调用。
         * 通过把传入的`observer`通过一个自定义的`ObserverWrapper`装修类。
         * 在`onChanged()`判断当前调用栈是否有`observeForever()`,存在时则不触发实际的`observer.onChanged()`。
         */
        private class BusLiveData<T> : MutableLiveData<T>() {
    
            // 反射缓存
            private companion object {
                private const val fieldObservers = "mObservers"
                private const val methodGet = "get"
                private const val fieldLastVersion = "mLastVersion"
                private const val fieldVersion = "mVersion"
                private val mCache = hashMapOf<String, Any>()
            }
    
            private val mRealMap = hashMapOf<Observer<*>, Observer<*>>()
    
            override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
                super.observe(owner, observer)
                setObserverVerToLiveDataVer(observer)
            }
    
            fun observeStick(owner: LifecycleOwner, observer: Observer<in T>) {
                super.observe(owner, observer)
            }
    
            override fun observeForever(observer: Observer<in T>) {
                super.observeForever(mRealMap.getOrPut(observer) {
                    WrapperObserver(observer)
                } as Observer<in T>)
            }
    
            fun observeStickyForever(observer: Observer<in T>) {
                super.observeForever(observer)
            }
    
            override fun removeObserver(observer: Observer<in T>) {
                if (mRealMap.containsKey(observer)) {
                    super.removeObserver(mRealMap.remove(observer) as Observer<T>)
                } else {
                    super.removeObserver(observer)
                }
            }
    
            private fun setObserverVerToLiveDataVer(observer: Observer<in T>) {
                val liveDataClass = LiveData::class.java
                try {
                    val mObserversField: Field = mCache.getOrPut(fieldObservers) {
                        val field = liveDataClass.getDeclaredField(fieldObservers)
                        field.isAccessible = true
                        field
                    } as Field
                    val mObservers = mObserversField[this]
    
                    val getMethod = mCache.getOrPut(methodGet) {
                        val method = mObservers.javaClass.getDeclaredMethod(methodGet, Any::class.java)
                        method.isAccessible = true
                        method
                    } as Method
    
                    val boundObserverEntry = getMethod.invoke(mObservers, observer)
                    var boundObserver: Any? = null
                    if (boundObserverEntry is Map.Entry<*, *>) {
                        boundObserver = boundObserverEntry.value
                    }
                    if (boundObserver == null) {
                        throw NullPointerException("LifecycleBoundObserver cant be null")
                    }
    
                    val mLastVersionField = mCache.getOrPut(fieldLastVersion) {
                        val wrapperClass: Class<in Any> = boundObserver.javaClass.superclass
                                ?: throw NullPointerException("Cant access ObserverWrapper.class")
                        val field = wrapperClass.getDeclaredField(fieldLastVersion)
                        field.isAccessible = true
                        field
                    } as Field
    
                    val mVersionField = mCache.getOrPut(fieldVersion) {
                        val field = liveDataClass.getDeclaredField(fieldVersion)
                        field.isAccessible = true
                        field
                    } as Field
    
                    mLastVersionField.set(boundObserver, mVersionField[this])
                } catch (e: Exception) {
                }
            }
        }
    
        /**
         * Observer包装类
         */
        private class WrapperObserver<T>(
                private val observer: Observer<T>
        ) : Observer<T> {
    
            private companion object {
                private const val clazz = "android.arch.lifecycle.LiveData"
                private const val func = "observeForever"
            }
    
            override fun onChanged(t: T) {
                if (!isCallOnObserve()) {
                    observer.onChanged(t)
                }
            }
    
            private fun isCallOnObserve(): Boolean {
                for (element in Thread.currentThread().stackTrace) {
                    if (clazz == element.className && func == element.methodName) {
                        return true
                    }
                }
                return false
            }
        }
    }
    

    使用方式:

    // 定义信息
    class Message
    
    // 订阅信息
    LiveDataBus.observe(Message::class.java, this, Observer { })
    LiveDataBus.observeForever(Message::class.java, Observer { })
    
    // 订阅粘性信息
    LiveDataBus.observeSticky(Message::class.java, this, Observer { })
    LiveDataBus.observeStickyForever(Message::class.java, Observer { })
    
    // 发布信息
    LiveDataBus.postMessage(Message())
    

    相关文章

      网友评论

          本文标题:深入理解AAC架构 - LiveDataBus 基于LiveDa

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