app开发中,我们常遇见不同页面之间要保持数据同步。送最初的onActivityResult,到后面的第三方库EventBus,RxBus,LiveEventBus。现在我们需要利用livedata自己写一个简单的消息总线。
对比过去:
onActivityResult:使用较为繁琐,并且在多页面下(比如栈:A,B,C。C的事件要传递给A就使用不方便了)。
EventBus:时代的眼泪,使用方便,但性能内存体积都是缺陷。
RxBus:不是库,是个文件,实现只有短短30行代码。结合Rxjava可以很方便的使用。
LiveEventBus:利用系统的livedata。体积小。且可以感知生命周期。
消息总线 | 延迟发送 | 有序接收消息 | Sticky | 生命周期感知 | 跨进程/APP | 线程分发 |
---|---|---|---|---|---|---|
EventBus | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ |
RxBus | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ |
LiveEventBus | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
它们都很优秀。但我们不用它们。自己写个简单的实现方案。主要参考LiveEventBus的核心逻辑。
代码:
LiveData
做消息,需要解决的是它的粘性问题(会接收注册前的消息)。网上有很多利用反射的方式修改lastVersion
的方法。这里提供一个不用反射的方式。
自己写一个,也叫LiveEventBus。😄
public class LiveEventBus {
private LiveEventBus() {
}
private static volatile LiveEventBus INSTANCE = null;
public static LiveEventBus getInstance() {
if (INSTANCE == null) {
synchronized (LiveEventBus.class) {
if (INSTANCE == null) {
INSTANCE = new LiveEventBus();
}
}
}
return INSTANCE;
}
private final Map<String, EventLiveData<?>> map = new HashMap<>();
@SuppressWarnings("unchecked")
public <T> MutableLiveData<T> get(String key, Class<T> clz) {
if (!map.containsKey(key)) {
EventLiveData<T> liveData = new EventLiveData<>();
map.put(key, liveData);
return liveData;
}
return (MutableLiveData<T>) map.get(key);
}
private static class EventLiveData<T> extends MutableLiveData<T> {
private int version = 0;
private final Map<Observer<?>, EventObserver<T>> observerMap = new HashMap<>();
/**
* postValue 最终也会调 setValue ,所以只需要在这里统计 version。
*/
@Override
public void setValue(T value) {
super.setValue(value);
version++;
}
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
super.observe(owner, getEventObserver(observer));
}
@Override
public void observeForever(@NonNull Observer<? super T> observer) {
super.observeForever(getEventObserver(observer));
}
@Override
public void removeObserver(@NonNull Observer<? super T> observer) {
EventObserver<T> eventObserver = observerMap.remove(observer);
if (eventObserver != null) super.removeObserver(eventObserver);
}
private EventObserver<T> getEventObserver(Observer<? super T> observer) {
if (observerMap.get(observer) != null) throw new RuntimeException("observer重复添加了!");
EventObserver<T> eventObserver = new EventObserver<>(observer, version);
observerMap.put(observer, eventObserver);
return eventObserver;
}
// 装饰者
private class EventObserver<E> implements Observer<E> {
private int observerVersion;
private final Observer<? super E> observer;
public EventObserver(Observer<? super E> observer, int version) {
this.observer = observer;
this.observerVersion = version;
}
@Override
public void onChanged(E t) {
if (observerVersion < EventLiveData.this.version) {
observerVersion = EventLiveData.this.version;
observer.onChanged(t);
}
}
}
}
}
使用姿势:
// 获取:(一般会把这步封装起来)
LiveEventBus .with<Event>(Key) //or
LiveEventBus .with(Key,Event::class.java)
// 订阅:
observe(owner,observer)// 绑定生命周期。
observeForever(observer) // 永久有效。
// 发布:
setValue(event) // 主线程。
postValue(event) // 子线程。
// 移除:
同liveData。
实战:
- 封装:同一模块的事件放在一起。key 与 event 对应。
- key 命名规范:模块名+子模块名+具体事件。
- 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() = LiveEventBus .with<ChangeGroupNameEvent>(CHANGE_GROUP_NAME)
/**
* 公告修改。
*/
fun changeNotification() = LiveEventBus .with<ChangeNotificationEvent>(CHANGE_NOTIFICATION)
/**
* 成员列表变换。
*/
fun changeMemberList() = LiveEventBus .with<ChangeMemberListEvent>(CHANGE_MEMBER_LIST)
/**
* 群聊列表变换。
*/
fun changeGroupList() = LiveEventBus .with<ChangeGroupListEvent>(CHANGE_GROUP_LIST)
/**
* 退出群聊。
*/
fun quitGroup() = LiveEventBus .with<QuitGroupEvent>(QUIT_GROUP)
/**
* 选择AT 成员。
*/
fun chooseAt() = LiveEventBus .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))
总结:
要点:
- 利用LiveData,感知生命周期的特性。
- 不接收注册观察之前的消息。(装饰者模式)
![](https://img.haomeiwen.com/i3262738/9debe69fca1baa9c.jpg)
网友评论