深入理解AAC架构 - LiveDataBus 基于LiveData实现的事件总线

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

本文主要内容:

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

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

  • Android消息总线的演进之路:用LiveDataBus替代RxBus、EventBus
    使用反射对Version进行管理
    使用字符串的方式进行消息管理

  • 基于LiveData实现事件总线思路和方案
    使用包装类对Version进行管理
    使用动态代理的方式进行信息管理

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


基本思路:

  • observe()
    即调用LiveData.observe(),基于LiveData的生命周期特性自动管理观察者。
  • observeForever()
    即调用LiveData.observeForever(),对无法提供LifecycleOwner的观察者进行支持。
  • removeObserver()
    即调用LiveData.removeObserver(),移除对应观察者。
  • postMessage()
    发布任意类型的消息,消息会通知所有关注此类型的观察者。
object LiveDataBus {
    private val mBus: MutableMap> = hashMapOf()

    fun  observe(channelClass: Class, owner: LifecycleOwner, observer: Observer) {
        getChannel(channelClass).observe(owner, observer)
    }

    fun  observeForever(channelClass: Class, observer: Observer) {
        getChannel(channelClass).observeForever(observer)
    }

    fun  removeObserver(channelClass: Class, observer: Observer) {
        getChannel(channelClass).removeObserver(observer)
    }

    fun  postMessage(message: T) {
        getChannel(message::class.java as Class).postValue(message)
    }

    private fun  getChannel(channelClass: Class): MutableLiveData {
        val channelName = channelClass.simpleName
        if (!mBus.containsKey(channelName)) {
            mBus[channelName] = MutableLiveData()
        }
        return mBus[channelName] as MutableLiveData
    }
}

使用方式:

// 定义信息
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>() }

    fun  observe(channel: Class, owner: LifecycleOwner, observer: Observer) {
        getChannel(channel).observe(owner, observer)
    }

    fun  observeSticky(channel: Class, owner: LifecycleOwner, observer: Observer) {
        getChannel(channel).observeStick(owner, observer)
    }

    fun  observeForever(channel: Class, observer: Observer) {
        getChannel(channel).observeForever(observer)
    }

    fun  observeStickyForever(channel: Class, observer: Observer) {
        getChannel(channel).observeStickyForever(observer)
    }

    fun  removeObserver(channelClass: Class, observer: Observer) {
        getChannel(channelClass).removeObserver(observer)
    }

    fun  postMessage(message: T) {
        getChannel(message::class.java as Class).postValue(message)
    }

    private fun  getChannel(channelClass: Class): BusLiveData {
        return mBus.getOrPut(channelClass.simpleName) {
            BusLiveData()
        } as BusLiveData
    }

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

        // 反射缓存
        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()
        }

        private val mRealMap = hashMapOf, Observer<*>>()

        override fun observe(owner: LifecycleOwner, observer: Observer) {
            super.observe(owner, observer)
            setObserverVerToLiveDataVer(observer)
        }

        fun observeStick(owner: LifecycleOwner, observer: Observer) {
            super.observe(owner, observer)
        }

        override fun observeForever(observer: Observer) {
            super.observeForever(mRealMap.getOrPut(observer) {
                WrapperObserver(observer)
            } as Observer)
        }

        fun observeStickyForever(observer: Observer) {
            super.observeForever(observer)
        }

        override fun removeObserver(observer: Observer) {
            if (mRealMap.containsKey(observer)) {
                super.removeObserver(mRealMap.remove(observer) as Observer)
            } else {
                super.removeObserver(observer)
            }
        }

        private fun setObserverVerToLiveDataVer(observer: Observer) {
            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 = 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(
            private val observer: Observer
    ) : Observer {

        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 基于LiveData实现的事件总线)