EventBus跟github上大神的不一样,是我大致根据自己的需求,然后简单实现的版本,主要满足个人需求。
/** * 消息处理者 * * @author jeff * */ public interface EventHandler { /** * 当接收到消息时回调此方法 * * @param event 发生的事件 */ public void onEvent(LocalEvent event); }
这个接口主要是事件发生的回调接口。
/** * 软件消息处理中心 * * @author jeff * */ public class EventBus { private static EventBus instance = new EventBus(); private List<EventHandler> handlers; private Handler uiThreadHandler; /** * 获取消息处理器 * * @return */ public static EventBus getDefault() { return instance; } private EventBus() { uiThreadHandler = new Handler(); handlers = new ArrayList<EventHandler>(); } /** * 添加关注本地广播 * * @param handler */ public void add(EventHandler handler) { synchronized (this) { handlers.add(handler); } } /** * 移除关注本地广播 * * @param handler */ public void remove(EventHandler handler) { synchronized (this) { handlers.remove(handler); } } /** * 同步发送一个消息广播 * * @param event */ public void post(LocalEvent event) { synchronized (this) { for(EventHandler handler : handlers) handler.onEvent(event); } } /** * 异步发送一个消息广播 * * @param event */ public void postInOtherThread(final LocalEvent event) { uiThreadHandler.post(new Runnable() { @Override public void run() { synchronized (this) { for(EventHandler handler : handlers) handler.onEvent(event); } } }); } /** * 异步显示一个toast消息 * * @param msg */ public void noticeMsg(final String msg) { uiThreadHandler.post(new Runnable() { @Override public void run() { ToastTool.showToast(msg); } }); } /** * 异步执行一个任务 * * @param runnable */ public void runningOnUiThread(Runnable runnable) { uiThreadHandler.post(runnable); } /** * 异步执行一个任务,带有延迟 * * @param runnable */ public void runningOnUiThread(Runnable runnable, int delay) { uiThreadHandler.postDelayed(runnable, delay); } }
EventBus就是整个本地事件处理的核心,用单件模式维护,为了简单直接用最简单的方式创建默认对象,而且还线程安全,如果有需求也可以把这个方式改为懒惰型。我会在application中调用下getDefault()方法保证EventBus在主线程中被初始化,因为我需要创建一个主线程的handler用来异步通信。
消息通知就是用非常常见的观察者模式,将每个观察者都记录在一个list里面,当然添加,移除和通知这个过程都是同步的确保线程安全。
消息的通知就有同步跟异步通知两种,因为我的通知大部分工作是通知界面更新,少部分其他的简单工作,所以我并不介意工作都放在主线程中处理,如果有工作量巨大则要考虑事件的接收者收到消息后在子线程处理,或者接口添加在其他线程收消息的接口,EventBus则判断EventHandler需要哪种方式,需要在其他线程的就添加到子线程然后再去通知事件发生。
最后的几个异步的方法主要是我在其他线程需要直接在主线程处理些东西的时候用的,比如显示一个toast,做些其他限定只能在主线程工作的事。
/** * 本地消息事件 * * @author jeff * */ public class LocalEvent { public static final int EVENT_TYPE_X = 101; public static final int EVENT_TYPE_XX = EVENT_TYPE_X + 1; private int eventType; private Object eventData; private String eventMsg; private int eventValue; public static LocalEvent getEvent(int eventType) { return getEvent(eventType, -1, "", null); } public static LocalEvent getEvent(int eventType, String eventMsg) { return getEvent(eventType, -1, eventMsg, null); } public static LocalEvent getEvent(int eventType, int eventValue) { return getEvent(eventType, eventValue, "", null); } public static LocalEvent getEvent(int eventType, int eventValue, String eventMsg) { return getEvent(eventType, eventValue, eventMsg, null); } public static LocalEvent getEvent(int eventType, int eventValue, String eventMsg, Object eventData) { LocalEvent event = new LocalEvent(); event.eventMsg = eventMsg; event.eventType = eventType; event.eventData = eventData; event.eventValue = eventValue; return event; } public int getEventType() { return eventType; } public void setEventType(int eventType) { this.eventType = eventType; } public Object getEventData() { return eventData; } public void setEventData(Object eventData) { this.eventData = eventData; } public String getEventMsg() { return eventMsg; } public void setEventMsg(String eventMsg) { this.eventMsg = eventMsg; } public int getEventValue() { return eventValue; } public void setEventValue(int eventValue) { this.eventValue = eventValue; } }
然后就是事件的模型了,主要由一个type,value,msg跟一个Object的data组成,参考handler的msg的数据内容实现,一般这四个参数也能满足大部分需求,如果有其他特殊需求可以再增加数据位。
接下去就是使用流程了,需要关注的fragment或activity在onCreate中EventBus.getDefault().add(this);在onDestory中EventBus.getDefault().remove(this);然后再实现EventHandler接口即可。
事件发生的地点则通过EventBus.getDefault().post(LocalEvent.getEvent(LocalEvent.EVENT_TYPE_X, value, msg));然后关注了事件的fragment或者activity的onEvent会被回调然后实现通知的效果。
这样的好处是使用起来非常的方便简单,也更加符合面向对象的思想,事件发生的地点只需要考虑将发生的事件传递出去而不关心谁想知道,EventBus则会将消息恰当的通知所有关心的人。这里的话我将事件类型的匹配没有放在EventBus中进行,因为这样更加简单,毕竟我总的EventHandler不会太多,如果本地通知的消息过多,可以考虑使用map来存储EventHandler,以事件类型为键,这样可以省去很多没用的通知,也可以加速匹配过程,只给EventHandler通知他们关心的事件而不是现在这样拿到了事件再去看看是不是关心,这样做也更像android的广播机制吧。