看到EventBus的第一眼,真的觉得很惊艳。
觉得它牛逼的地方有两点:
1.支持指定事件处理的线程。避免在处理事件的时候还要自己写代码跳转到不同的线程,能简化不少工作。
2.没有使用interface,不同的事件处理函数,可以采用不同的名称,方便区分,方便不同事件的处理逻辑分离。很棒吧。代码可读性提升了。
进一步深入研究发现几点很不爽的地方,以至于我放弃它,自己另外实现:
1.强引用,注册之后,必须保证unregister。实际使用的时候,很难保证所有人都去unregister。
2.事件都是根据类型来判断的,特别还是支持继承关系。这个看似很强大,实际上我感觉如果真这么用,事件不断增加,继承关系的层级越来越多,以后的维护和调试都是恶梦。不过我觉得客户端完全不需要这么复杂的结构,没人会这么用。反而我本身的需求是,同样类型的对象表示不同的事件。
3.方法名称后缀来指定线程以及监听消息。假如出现拼写错误,要找出个问题,可能要花不少事件。
说了这么多。那么我要实现的EventBus,将针对上述3点吐糟来做改进:
1.使用weakreference,即使没有unregister也不干扰对象释放;
2.事件类型通过字符串标识,具体事件相关的数据直接使用Object类型,即使没有任何数据也行。就像下班了这个简单的事件,你告诉我下班了,不需要其它任何附加信息,我也知道我该关掉电脑然后回家。
3.我们对方法名称没有任何要求,我们使用注解来标识事件处理函数和指定处理线程。
下面开工,首先定义一个名为OnEvent的注解,注册有两个参数,枚举类型的threadMode用来指定处理线程。字符串类型的eventType用来指定事件类型
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OnEvent {
ThreadMode threadMode() default ThreadMode.Async;
String eventType();
}
public enum ThreadMode {
/**
* deliver event in main thread(UI thread)
*/
MainThread,
/**
* deliver event in thread that post the event
*/
PostThread,
/**
* deliver event in background threads,
* not the post one and main thread
*/
Async
}
接着实现我们自己的EventBus类:
主要方法有register方法来注册事件监听,unRegister来取消注册,postDelayed来延时传递事件,post来传递事件。
public class EventBus{
……
public void register(Object receiver) {
if(receiver==null)return;
List<ReceiverMeta> metas = ReceiverParser.parse(receiver);
storage.addReceiver(receiver, metas);
}
public void unRegister(Object receiver) {
if(receiver==null)return;
List<ReceiverMeta> metas = ReceiverParser.parse(receiver);
storage.removeReceiver(receiver, metas);
}
……
public void postDelayed(Object event, String eventType, long mills) {
try {
bgPoster.postEventDelayed(event,eventType, mills);
} catch (InterruptedException ex) {
post(event,eventType);
}
}
public void post(Object event,String eventType) {
List<ReceiverWrapper> receiverWrappers = storage.getReceivers(eventType);
if (receiverWrappers != null) {
for (ReceiverWrapper wrapper : receiverWrappers) {
switch (wrapper.meta.threadMode) {
case PostThread:
deliverThroughCurThread(wrapper, event);
break;
case MainThread:
deliverToMainThread(wrapper, event);
break;
case Async:
deliverAsynchronized(wrapper, event);
break;
}
}
}
}
……
}
1.register
register调用ReceiverParser类的静态方法parse来解析对象监听的事件以及方法。
该方法会遍历对象类型中所有的方法,找出其中public以及有@OnEvent注解的方法,且没有参数或者只有一个Object类型参数方法。每个解析出来的Method都会被封装成一个个的ReceiverMeta对象。最后返回的是一个List<RecevierMeta>实例。
register获得List<ReceiverMeta>对象,再调用ReceiverStorage的对象的addReceiver方法保存监听信息,在addReceiver方法中,监听者会被WeakReference包装起来。使用弱引用,避免干扰正常的对象回收。监听者的弱引用以及ReceiverMeta会被封装成ReceiverWrapper对象中,然后调用addReceiverWrapper方法,将ReceiverWrapper对象存入到列表中,列表再存入到hash map中,key为事件名称。
2.unRegister
unRegister同样调用ReceiverParser类的parse方法解析出ReceiverMeta列表,调用ReceiverStorage的removeWrapper方法一个个的移除ReceiverWrapper对象来取消注册。
3.postDelayed
postDelayed使用BackGroundPoster实例的postEventDelayed来实现延时传递。
public class BackGroundBus {
private Looper looper;
private final Thread thread;
private Handler handler;
private final EventBus eventBus;
private final CountDownLatch cdl=new CountDownLatch(1);
public BackGroundBus(final EventBus eventBus){
this.eventBus=eventBus;
thread = new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
BackGroundBus.this.looper = Looper.myLooper();
BackGroundBus.this.handler=new Handler(looper){
@Override
public void handleMessage(Message msg) {
if(msg.obj!=null&&msg.obj instanceof DelayedEvent){
DelayedEvent delayedEvent=(DelayedEvent)msg.obj;
eventBus.post(delayedEvent.event,delayedEvent.eventType);
}
}
};
cdl.countDown();
Looper.loop();
}
});
thread.start();
}
public void postEventDelayed(Object event,String eventType,long millis) throws InterruptedException{
cdl.await();
DelayedEvent delayedEvent=new DelayedEvent();
delayedEvent.event=event;
delayedEvent.eventType=eventType;
Message msg=handler.obtainMessage();
msg.obj=delayedEvent;
handler.sendMessageDelayed(msg, millis);
}
public void stop() throws InterruptedException {
cdl.await();
looper.quit();
}
}
BackGroupPoster 通过内建的Thread以及对应的Looper来实现事件的循环处理,最终还是通过EventBus实例的post方法来传递事件。
4.post
post方法通过事件名称(字符串)来找出ReceiverStorage实例中存储的ReceiverWrapper对象,然后循环处理,通过ReceiverWrapper对象指定的线程来传递事件。
post又分别通过下面三个方法,将事件通过当前线程、主线程、或者异步的方式传递。
private void deliverThroughCurThread(final ReceiverWrapper wrapper, final Object event) {
try {
wrapper.receive(event);
} catch (Exception e) {
onException(e);
}
}
private void deliverToMainThread(final ReceiverWrapper wrapper, final Object event) {
mainThreadPoster.deliverEvent(wrapper, event);
}
private void deliverAsynchronized(final ReceiverWrapper wrapper, final Object event) {
executor.execute(new Runnable() {
@Override
public void run() {
try {
wrapper.receive(event);
} catch (Exception e) {
onException(e);
}
}
});
}
5.错误监听
/**
* 异常监听器
*/
public static interface ExceptionListenner{
void onException(Exception e);
}
通过EventBus实例的setExListenner方法可以指定异常监听器来处理异常。
之所以使用这种模式,是为了避免异常影响事件的继续传递。
6.postDelayed需要注意的地方
通过postDelayed传递的事件是无法实现当前线程传递的,如果制定了当前线程传递,最后是在BackGroundPoster的线程中传递的。
最后,附上源代码:SimpleEventBus