LiveData实现消息总线

app开发中,我们常遇见不同页面之间要保持数据同步。送最初的onActivityResult,到后面的第三方库EventBus,RxBus,LiveEventBus。现在我们需要利用livedata自己写一个简单的消息总线。

对比过去:

onActivityResult:使用较为繁琐,并且在多页面下(比如栈:A,B,C。C的事件要传递给A就使用不方便了)。
EventBus:时代的眼泪,使用方便,但性能内存体积都是缺陷。
RxBus:不是库,是个文件,实现只有短短30行代码。结合Rxjava可以很方便的使用。
LiveEventBus:利用系统的livedata。体积小。且可以感知生命周期。

消息总线 延迟发送 有序接收消息 Sticky 生命周期感知 跨进程/APP 线程分发
EventBus
RxBus
LiveEventBus

它们都很优秀。但我们不用它们。自己写个简单的实现方案。主要参考LiveEventBus的核心逻辑。

代码:

短短50多行代码(去掉注释和空行也就30行左右)。

object EventHelper {
    private val map = HashMap<String, EventLiveData<*>>()
    @Suppress("UNCHECKED_CAST")
    fun <T> with(key: String, type: Class<T>? = null): EventLiveData<T> {
        if (!map.containsKey(key)) {
            map[key] = EventLiveData<T>()
        }
        return map[key] as? EventLiveData<T>
                ?: throw RuntimeException("cannot cast EventLiveData of " + type.toString())
    }
    /**
     * 记录版本的 MutableLiveData。
     */
    class EventLiveData<T> : MutableLiveData<T>() {
        var version: Int = 0
            private set
        /**
         * postValue 最终也会调 setValue ,所以只需要在这里统计 version。
         */
        override fun setValue(value: T) {
            version++
            super.setValue(value)
        }
        /**
         * 订阅事件。绑定生命周期。返回 Observer 方便主动移除观察。
         */
        fun observeEvent(owner: LifecycleOwner, onEvent: (T) -> Unit): Observer<T> {
            return EventObserver(onEvent).apply { super.observe(owner, this) }
        }
        /**
         * 订阅事件。永久有效。返回 Observer 方便主动移除观察。
         */
        fun observeForeverEvent(onEvent: (T) -> Unit): Observer<T> {
            return EventObserver(onEvent).apply { super.observeForever(this) }
        }
        /**
         * 不接收创建之前的消息。
         */
        inner class EventObserver<T>(val onEvent: (T) -> Unit) : Observer<T> {
            private var observerVersion = this@EventLiveData.version
            override fun onChanged(t: T) {
                if (observerVersion < this@EventLiveData.version) {
                    observerVersion = this@EventLiveData.version
                    onEvent(t)
                }
            }
        }
    }
}

使用姿势:

// 获取:(一般会把这步封装起来)
EventHelper.with<Event>(Key) //or 
EventHelper.with(Key,Event::class.java)
// 订阅:
observeEvent(owner){ event -> do something } // 绑定生命周期。
observeForeverEvent{ event -> do something } // 永久有效。
// 发布:
setValue(event) // 主线程。
postValue(event) // 子线程。
// 移除:
同liveData。

实战:

  1. 封装:同一模块的事件放在一起。key 与 event 对应。
  2. key 命名规范:模块名+子模块名+具体事件。
  3. event类上加上ID:例如:ChangeGroupNameEvent加上groupCode明确是那个群名称变了。
// 示例
object IMEventHelper {
    private const val CHANGE_GROUP_NAME = "im/group/changeGroupName"
    private const val CHANGE_NOTIFICATION = "im/group/changeNotification"
    private const val CHANGE_MEMBER_LIST = "im/group/changeMemberList"
    private const val CHANGE_GROUP_LIST = "im/group/changeGroupList"
    private const val QUIT_GROUP = "im/group/quitGroup"
    private const val CHOOSE_AT = "im/group/chooseAt"
    /**
     * 群名称修改。
     */
    fun changeGroupName() = EventHelper.with<ChangeGroupNameEvent>(CHANGE_GROUP_NAME)
    /**
     * 公告修改。
     */
    fun changeNotification() = EventHelper.with<ChangeNotificationEvent>(CHANGE_NOTIFICATION)
    /**
     * 成员列表变换。
     */
    fun changeMemberList() = EventHelper.with<ChangeMemberListEvent>(CHANGE_MEMBER_LIST)
    /**
     * 群聊列表变换。
     */
    fun changeGroupList() = EventHelper.with<ChangeGroupListEvent>(CHANGE_GROUP_LIST)
    /**
     * 退出群聊。
     */
    fun quitGroup() = EventHelper.with<QuitGroupEvent>(QUIT_GROUP)
    /**
     * 选择AT 成员。
     */
    fun chooseAt() = EventHelper.with<AtMemberEvent>(CHOOSE_AT)
}

event类:

class ChangeGroupNameEvent(val groupCode: String, val newName: String)

使用:

// 在 fragment 初始化里订阅事件。
IMEventHelper
    .changeGroupName()
    .observeEvent(this) { vm.changeName(it) }
// 在 其它地方发布事件。
IMEventHelper
    .changeGroupName()
    .postValue(ChangeGroupNameEvent(groupCode, newName))

总结:

要点:

  1. 利用LiveData,感知生命周期的特性。
  2. 不接收注册观察之前的消息。
配一张图

推荐阅读更多精彩内容