前言
本文主要从源码的角度来分析事件总线 EventBus 的实现原理, EventBus 是常用的消息传递的方式之一,其他常见的消息传递的方式还包括 Handler
、BroadcastReceiver
、Listener
。通过本篇你在掌握 EventBus 基本使用的基础之上,能够掌握 EventBus 的实现原理。下面的框架图可以清晰的看到这一点。
一、定义事件类
作为事件的发布者,需要定义所发布的事件的类:
public class MessageEvent {
private String msg;
public MessageEvent(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
二、注册/取消注册响应事件
作为事件的订阅者,需要把响应事件的对象注册到EventBus当中:EventBus.getDefault().register(obj)
当不需要处理某个类型的事件的时候,取消对这个事件的监听:EventBus.getDefault().unregister(obj)
三、声明和注释订阅方法,选择指定线程模式
作为事件的订阅者,需要定义事件的响应方法,方法名称可以随意取,方法的形参类型,必须和监听的事件对象类型一致:
@Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(this, event.getMsg (),
Toast.LENGTH_SHORT).show();
}
3.1 四种线程模式
事件订阅者可以通过注解的方式选择处理事件的方法所在的线程:
-
PostThread: 如果事件处理函数指定了线程模型为PostThread,那么事件的发布和接收处理会在同一个线程当中。
-
BackgroundThread: 如果事件处理函数指定了线程模型为BackgroundThread,那么如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的子线程中运行,如果事件发布本来就是非UI线程中发布出来 的,那么该事件处理函数直接在发布事件的线程中执行。
-
MainThread: 如果事件处理函数指定了线程模型为MainThread,那么不论事件对象是在哪个线程中发布出来的,该事件处理函数都会在UI线程中执行。
-
Async: 如果事件处理函数指定了线程模型为Async,那么无论事件在哪个线程发布,该事件处理函数都会在新建的子线程中执行。
3.2 黏性事件
通过注解的方式设置sticky为true,那么事件处理函数则可以处理上一次的事件对象:
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
四、EventBus 3.0源码详解
4.1 注册流程
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
* <p/>
* Subscribers have event handling methods that must be annotated by {@link Subscribe}.
* The {@link Subscribe} annotation also allows configuration like {@link
* ThreadMode} and priority.
*/
public void register(Object subscriber) {
//通过注册的对象得到其类的class对象
Class<?> subscriberClass = subscriber.getClass();
//通过类的class对象得到此对象的订阅方法列表
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod :subscriberMethods) {
//线程同步,遍历订阅方法列表,注册每一个订阅方法
subscribe(subscriber, subscriberMethod);
}
}
}
代码subscriberMethodFinder.findSubscriberMethods(subscriberClass)获取订阅方法列表具体如下:
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//在缓存中查找此class对象对应的订阅方法列表
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//是否忽略注解器生成的MyEventBusIndex类
if (ignoreGeneratedIndex) {
//通过反射机制得到订阅者类class对象对应的订阅事件方法列表
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//从注解器生成的MyEventBusIndex类中获得订阅类的订阅方法列表
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
//缓存此class对象的订阅方法列表
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
通过反射机制获取订阅方法列表:
private