项目地址.
这一篇我们主要是通过LiveData
来实现事件总线,类似EventBus
LiveData
和Handler
类似,都能实现事件的分发,Handler
我们平时都使用过,调用sendMessage
方法发送,我们会在handleMessage
的方法中处理发送的事件,
Handler mHandler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
};
mHandler.sendMessage(msg)
这个是立即执行的,即使我们这个页面不可见也会去执行,而LiveData
是在我们观察者活跃的时候才会派发事件,通常这个LiveData
用于单页面的消息分发,页面间的消息传递怎么办呢?我们可以使用单例,使用Key-Value
形式管理LiveData
,同时我们这个事件总线既可以发送一次性事件可以也可以发送粘性事件
//正常的事件
LiveData mLiveData=null;
mLiveData.observer(this,new Observer<User>){
void onChanged(User user){
}
}
mLiveData.postValue(data);
//黏性事件。先发送。后注册监听
LiveData mLiveData=null;
mLiveData.postValue(data);
mLiveData.observer(this,new Observer<User>){
void onChanged(User user){
}
}
我们新建一个LiveDataBus
类,同时实现单例
/**
* LiveData实现事件总线
*/
public class LiveDataBus {
private static class Lazy {
static LiveDataBus sLiveDataBus = new LiveDataBus();
}
public static LiveDataBus get() {
return Lazy.sLiveDataBus;
}
}
消息类型会有很多种,这里我们使用HashMap
来存储消息类型和与之对应的LiveData
private ConcurrentHashMap<String, StickyLiveData> mHashMap = new ConcurrentHashMap<>();
public class StickyLiveData<T> extends LiveData<T> {
}
我们发送事件肯定需要这个对应的name
和data
,这里我们还需要记录下发送的次数,所以我们给这个StickyLiveData
添加三个属性
private String mEventName;
private T mStickyData;
private int mVersion = 0;
public StickyLiveData(String eventName) {
mEventName = eventName;
}
我们每发送一次mVersion
都加一
@Override
public void setValue(T value) {
mVersion++;
super.setValue(value);
}
@Override
public void postValue(T value) {
mVersion++;
super.postValue(value);
}
我们需要支持同步发送一条粘性事件
public void setStickyData(T stickyData) {
this.mStickyData = stickyData;
setValue(stickyData);
}
public void postStickyData(T stickyData) {
this.mStickyData = stickyData;
postValue(stickyData);
}
我们还需要复写observe
方法,我们需要把粘性事件分发给那些关心粘性数据的observer
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
observerSticky(owner, observer, false);
}
public void observerSticky(LifecycleOwner owner, Observer<? super T> observer, boolean sticky) {
super.observe(owner, new WrapperObserver(this, observer, sticky));
owner.getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
mHashMap.remove(mEventName);
}
}
});
}
private class WrapperObserver<T> implements Observer<T> {
private StickyLiveData<T> mLiveData;
private Observer<T> mObserver;
private boolean mSticky;
//标记该liveData已经发射几次数据了,用以过滤老数据重复接收
private int mLastVersion = 0;
public WrapperObserver(StickyLiveData liveData, Observer<T> observer, boolean sticky) {
mLiveData = liveData;
mObserver = observer;
mSticky = sticky;
//比如先使用StickyLiveData发送了一条数据。StickyLiveData#version=1
//那当我们创建WrapperObserver注册进去的时候,就至少需要把它的version和 StickyLiveData的version保持一致
//用以过滤老数据,否则 岂不是会收到老的数据?
mLastVersion = mLiveData.mVersion;
}
@Override
public void onChanged(T t) {
//如果当前observer收到数据的次数已经大于等于了StickyLiveData发送数据的个数了则return
/**
* observer.mLastVersion >= mLiveData.mVersion
* 这种情况 只会出现在,我们先行创建一个liveData发射了一条数据。此时liveData的mversion=1.
*
* 而后注册一个observer进去。由于我们代理了传递进来的observer,进而包装成wrapperObserver,此时wrapperObserver的lastVersion 就会跟liveData的mversion 对齐。保持一样。把wrapperObserver注册到liveData中。
*
* 根据liveData的原理,一旦一个新的observer 注册进去,也是会尝试把数据派发给他的。这就是黏性事件(先发送,后接收)。
*
* 但此时wrapperObserver的lastVersion 已经和 liveData的version 一样了。由此来控制黏性事件的分发与否
*/
if (mLastVersion >= mLiveData.mVersion) {
//但如果当前observer它是关心 黏性事件的,则给他。
if (mSticky && mLiveData.mStickyData != null) {
mObserver.onChanged(mLiveData.mStickyData);
}
return;
}
mLastVersion = mLiveData.mVersion;
mObserver.onChanged(t);
}
}
我们还需要写一个根据消息事件类型获取StickyLiveData
的方法
public StickyLiveData with(String eventName) {
StickyLiveData liveData = mHashMap.get(eventName);
if (liveData == null) {
liveData = new StickyLiveData(eventName);
mHashMap.put(eventName, liveData);
}
return liveData;
}
Ok,这样我们整个的事件总线就写完了