EventBus 是一个 Android 事件发布/订阅框架。
传统的事件传递方式包括:Handler(消息处理机制,一般用于更新UI)、BroadCastReceiver(广播接收者)、Interface 回调。
@Override
public void onCreate() {
//3.0版本的注册,2.x不再介绍
EventBus.getDefault().register(this);
}
我们可以自定义自己的事件类,例如:
public class CreateFolderEvent {
//一个创建文件夹的事件
public File folder;
public String parentPath;
public CreateFolderEvent(File folder, String parentPath) {
this.folder = folder;
this.parentPath = parentPath;
}
}
注册之后,我们接着编写响应事件的方法,如下:
//threadMode和sticky使用下文会讲
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void onReceiveCreateFolderEvent(CreateFolderEvent event) {
Log.e("Subscribe",event.parentPath);
}
通过EventBus的post()方法来发送事件,对应的接收方就会收到信息并通过Event来获取传递的对象.EventBus或者通过postSticky()来发送一个粘性事件.
粘性事件:何为黏性事件呢?简单讲,就是在发送事件之后再订阅该事件也能收到该事件,跟黏性广播类似。
举例场景:如我想发送一个事件给一个Activity,但是那个activity还没有创建。又想让activity创建时收到,可以用postSticky()。
示例如下:
private void updateCreateFolderUI(String message) {
File item = new File();
mCurrentPath="/Sdcard/";
EventBus().getDefault().post(new CreateFolderEvent(item, mCurrentPath));
//或者是
EventBus().getDefault().postSticky(new CreateFolderEvent(item, mCurrentPath));
}
一般在onDestory()方法中取消订阅:防止内存溢出。
@Override
public void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
从中我们也可以看出大部分类都与 EventBus 直接关联。上部分主要是订阅者相关信息,中间是 EventBus 类,下面是发布者发布事件后的调用。
使用方法介绍完了,下面让我们来对EventBus进行简单的源码分析
EventBus的订阅者、发布者、EventBus 关系图与事件响应流程流程,通过我们熟悉的使用方法来深入到EventBus的实现内部并理解其实现原理.
EventBus 类负责所有对外暴露的 API,其中的 register()、post()、unregister() 函数配合上自定义的 EventType 及事件响应函数即可完成核心功能
一般情况下我们都是通过EventBus.getDefault()获取到EventBus对象,进入源码查看其实现:
public static EventBus getDefault() {
if(defaultInstance == null) {
Class var0 = EventBus.class;
synchronized(EventBus.class) {
if(defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
这里获得对象的模式是常用的单例模式了,目的是为了保证getDefault()得到的都是同一个实例。如果不存在实例,则会调用EventBus的构造方法:
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
public static EventBusBuilder builder() {
return new EventBusBuilder();
}
EventBus(EventBusBuilder builder) {
this.currentPostingThreadState = new ThreadLocal() {
protected EventBus.PostingThreadState initialValue() {
return new EventBus.PostingThreadState();
}
};
//key:订阅的事件,value:订阅这个事件的所有订阅者集合
//private final Map, CopyOnWriteArrayList> subscriptionsByEventType;
subscriptionsByEventType = new HashMap<>();
//key:订阅者对象,value:这个订阅者订阅的事件集合
//private final Map
typesBySubscriber = new HashMap<>();
//粘性事件 key:粘性事件的class对象, value:事件对象
//private final Map, Object> stickyEvents;
stickyEvents = new ConcurrentHashMap<>();
//事件主线程处理
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
//事件 Background 处理
backgroundPoster = new BackgroundPoster(this);
//事件异步线程处理
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
//订阅者响应函数信息存储和查找类
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
//是否支持事件继承
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
//此处参考http://www.jianshu.com/p/f057c460c77e
}
从上面代码可以看出EventBus通过初始化一个EventBusBuilder()对象来初始化EventBus的一些配置。
在获取到EventBus对象以后,我们就可以将订阅者注册到EventBus中。
register()方法的实现
public void register(Object subscriber) {
//首先获得订阅者的class对象
Class subscriberClass = subscriber.getClass();
/通过subscriberMethodFinder来找到订阅者订阅了哪些事件.返回一个SubscriberMethod对象的List,SubscriberMethod
//里包含了这个方法的Method对象,以及将来响应订阅是在哪个线程的ThreadMode
//以及订阅的事件类型eventType,以及订阅的优
//先级priority,以及是否接收粘性sticky事件的boolean值.
List subscriberMethods = this.subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized(this) {
Iterator var5 = subscriberMethods.iterator();
while(var5.hasNext()) {
SubscriberMethod subscriberMethod = (SubscriberMethod)var5.next();
//订阅
this.subscribe(subscriber, subscriberMethod);
}
}
}
SubscriberMethodFinder类就是用来查找和缓存订阅者响应函数的信息的类。
3.0版本中,EventBus提供了一个EventBusAnnotationProcessor注解处理器来在编译期通过读取@Subscribe()注解并解析,处理其中所包含的信息,然后生成java类来保存所有订阅者关于订阅的信息,这样就比在运行时使用反射来获得这些订阅者的信息速度要快.
SubscriberMethod里包含了需要执行subscribe()的信息,下面进入findSubscriberMethods()方法源码中查看:
List findSubscriberMethods(Class> subscriberClass) {
//先从METHOD_CACHE取看是否有缓存,key:保存订阅类的类名,value:保存类中订阅的方法数据,
List subscriberMethods = (List)METHOD_CACHE.get(subscriberClass);
if(subscriberMethods != null) {
return subscriberMethods;
} else {
//是否忽略注解器生成的MyEventBusIndex类
if(this.ignoreGeneratedIndex) {
//利用反射来读取订阅类中的订阅方法信息
subscriberMethods = this.findUsingReflection(subscriberClass);
} else {
subscriberMethods = this.findUsingInfo(subscriberClass);
}
if(subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass + " and its super classes have no public methods with the @Subscribe annotation");
} else {
//保存进METHOD_CACHE缓存
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
}
下面我们来看findUsingInfo()方法的源码实现:
private List findUsingInfo(Class> subscriberClass) {
SubscriberMethodFinder.FindState findState = this.prepareFindState();
//FindState 用来做订阅方法的校验和保存
findState.initForSubscriber(subscriberClass);
for(; findState.clazz != null; findState.moveToSuperclass()) {
findState.subscriberInfo = this.getSubscriberInfo(findState);
if(findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
SubscriberMethod[] var4 = array;
int var5 = array.length;
for(int var6 = 0; var6 < var5; ++var6) {
SubscriberMethod subscriberMethod = var4[var6];
if(findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
this.findUsingReflectionInSingleClass(findState);
}
}
return this.getMethodsAndRelease(findState);
}
findUsingInfo是通过查找我们上面所说的EventBusIndex类中的信息,来转换成List从而获得订阅类的相关订阅函数的各种信息.
接着让我们进入findUsingReflection()方法:
private List findUsingReflection(Class> subscriberClass) {
SubscriberMethodFinder.FindState findState = this.prepareFindState();
findState.initForSubscriber(subscriberClass);
while(findState.clazz != null) {
//通过反射来获得订阅方法信息
this.findUsingReflectionInSingleClass(findState);
//查找父类的订阅方法
findState.moveToSuperclass();
}
//获取findState中的SubscriberMethod(订阅方法List)并返回
return this.getMethodsAndRelease(findState);
}
FindState类做订阅方法的校验和保存,FIND_STATE_POOL静态数组来保存FindState对象,FindState复用,避免重复创建过多的对象.最终通过findUsingReflectionInSingleClass()来具体获得相关订阅方法的信息:
private void findUsingReflectionInSingleClass(SubscriberMethodFinder.FindState findState) {
Method[] methods;
try {
//获得声明的所有方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable var12) {
//异常则获取公开方法
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
Method[] th = methods;
int var4 = methods.length;
for(int var5 = 0; var5 < var4; ++var5) {
Method method = th[var5];
//返回int类型值表示该字段的修饰符
int modifiers = method.getModifiers();
if((modifiers & 1) != 0 && (modifiers & 5192) == 0) {
Class[] var13 = method.getParameterTypes();
if(var13.length == 1) {
Subscribe methodName1 = (Subscribe)method.getAnnotation(Subscribe.class);
if(methodName1 != null) {
Class eventType = var13[0];
if(findState.checkAdd(method, eventType)) {
ThreadMode threadMode = methodName1.threadMode();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, methodName1.priority(), methodName1.sticky()));
}
}
} else if(this.strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String var14 = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + var14 + "must have exactly 1 parameter but has " + var13.length);
}
} else if(this.strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
至此,在register()方法中,订阅类的所有SubscriberMethod都已经被保存了,最后再通过getMethodsAndRelease()返回List。
接着,我们查看register()方法中的订阅事件
synchronized(this) {
//获取到所有的订阅方法,一一订阅
Iterator var5 = subscriberMethods.iterator();
while(var5.hasNext()) {
SubscriberMethod subscriberMethod = (SubscriberMethod)var5.next();
this.subscribe(subscriber, subscriberMethod);
}
}
进入subscribe(subscriber, subscriberMethod);源码查看下。
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
////获取订阅的事件类型 普通事件和粘性事件
Class eventType = subscriberMethod.eventType;
////创建Subscription对象
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//从subscriptionsByEventType里检查是否已经添加过该Subscription
CopyOnWriteArrayList subscriptions = (CopyOnWriteArrayList)this.subscriptionsByEventType.get(eventType);
if(subscriptions == null) {
//未添加则创建
subscriptions = new CopyOnWriteArrayList();
this.subscriptionsByEventType.put(eventType, subscriptions);
} else if(subscriptions.contains(newSubscription)) {
//如果添加过就抛出异常
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
}
//根据优先级priority来添加Subscription对象
int size = subscriptions.size();
for(int subscribedEvents = 0; subscribedEvents <= size; ++subscribedEvents) {
if(subscribedEvents == size || subscriberMethod.priority > ((Subscription)subscriptions.get(subscribedEvents)).subscriberMethod.priority) {
subscriptions.add(subscribedEvents, newSubscription);
break;
}
}
//将订阅者对象以及订阅的事件保存到typesBySubscriber里.
// private final Map
Object var13 = (List)this.typesBySubscriber.get(subscriber);
if(var13 == null) {
var13 = new ArrayList();
this.typesBySubscriber.put(subscriber, var13);
}
((List)var13).add(eventType);
//如果事件的类型是sticky,则立即分发sticky事件
if(subscriberMethod.sticky) {
if(this.eventInheritance) {
//eventInheritance 表示是否分发订阅了响应事件类父类事件的方法
// Existing sticky events of all subclasses of eventType have to be considered.
// Note: Iterating over all events may be inefficient with lots of sticky events,
// thus data structure should be changed to allow a more efficient lookup
// (e.g. an additional map storing sub classes of super classes: Class -> List).
Set stickyEvent = this.stickyEvents.entrySet();
Iterator var9 = stickyEvent.iterator();
while(var9.hasNext()) {
Entry entry = (Entry)var9.next();
Class candidateEventType = (Class)entry.getKey();
if(eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent1 = entry.getValue();
//分发sticky事件给订阅者
this.checkPostStickyEventToSubscription(newSubscription, stickyEvent1);
}
}
} else {
Object var14 = this.stickyEvents.get(eventType);
//分发sticky事件给订阅者
this.checkPostStickyEventToSubscription(newSubscription, var14);
}
}
}
下面抄图展示register() 函数流程:
public void postSticky(Object event) {
//最终会调用post(Object event)
Map var2 = this.stickyEvents;
synchronized(this.stickyEvents) {
//将event放入 private final Map, Object> stickyEvents的map中
this.stickyEvents.put(event.getClass(), event);
}
this.post(event);
}
public void post(Object event) {
//得到当前线程的postingState状态
EventBus.PostingThreadState postingState = (EventBus.PostingThreadState)this.currentPostingThreadState.get();
//获取当前线程的事件队列
List eventQueue = postingState.eventQueue;
eventQueue.add(event);
if(!postingState.isPosting) {
//判断是否是主线程
postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
postingState.isPosting = true;
if(postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while(!eventQueue.isEmpty()) {
//若果不是空,则分发事件
this.postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
currentPostingThreadState的实现是一个包含了PostingThreadState的ThreadLocal对象
private final ThreadLocal currentPostingThreadState;
EventBus(EventBusBuilder builder) {
this.currentPostingThreadState = new ThreadLocal() {
protected EventBus.PostingThreadState initialValue() {
return new EventBus.PostingThreadState();
}
};
}
PostingThreadState类如下:
static final class PostingThreadState {
final List
ThreadLocal用于实现在不同的线程中存储线程私有数据的类。在多线程的环境中,当多个线程需要对某个变量进行频繁操作,同时各个线程间不需要同步,此时,各个子线程只需要对存储在当前线程中的变量的拷贝进行操作即可,程序的运行效率会很高,即所谓的空间换时间。
Android版的ThreadLocal和java原生的ThreadLocal有一定的差别,android版的进行了一些优化设计,通过内部类Values中的Object数组来存储ThreadLocal的弱引用和线程的局部数据对象;而java版的是以MAP的方式来存储。
具体请查看Android开发之ThreadLocal原理深入理解
接下来我们进入postSingleEvent(eventQueue.remove(0), postingState)去查看:
try {
while(!eventQueue.isEmpty()) {
this.postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
postSingleEvent(eventQueue.remove(0), postingState)包含的几个主要方法一并列出:
private void postSingleEvent(Object event, EventBus.PostingThreadState postingState) throws Error {
Class eventClass = event.getClass();
boolean subscriptionFound = false;
//是否触发订阅了该事件(eventClass)的父类,以及接口的类的响应方法.
if(this.eventInheritance) {
//查找eventClass类所有的父类以及接口
List eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for(int h = 0; h < countTypes; ++h) {
Class clazz = (Class)eventTypes.get(h);
//右边有一个为true,subscriptionFound属性为true
subscriptionFound |= this.postSingleEventForEventType(event, postingState, clazz);
}
} else {
//post单个事件
subscriptionFound = this.postSingleEventForEventType(event, postingState, eventClass);
}
if(!subscriptionFound) {
//如果未发现
if(this.logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if(this.sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) {
//满足上述条件则发送空事件
this.post(new NoSubscriberEvent(this, event));
}
}
}
private boolean postSingleEventForEventType(Object event, EventBus.PostingThreadState postingState, Class> eventClass) {
CopyOnWriteArrayList subscriptions;
synchronized(this) {
//获取订阅了这个事件的Subscription列表.
subscriptions = (CopyOnWriteArrayList)this.subscriptionsByEventType.get(eventClass);
}
if(subscriptions != null && !subscriptions.isEmpty()) {
Iterator var5 = subscriptions.iterator();
while(var5.hasNext()) {
Subscription subscription = (Subscription)var5.next();
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
//一个个将事件分发给订阅者
this.postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
//将postingState置为初始状态
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if(aborted) {
//如果被中断,结束整个循环体
break;
}
}
return true;
} else {
return false;
}
}
//postToSubscription()通过不同的threadMode在不同的线程里invoke()订阅者的方法
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch(null.$SwitchMap$com$inno$eventbus$ThreadMode[subscription.subscriberMethod.threadMode.ordinal()]) {
case 1:
this.invokeSubscriber(subscription, event);
break;
case 2:
if(isMainThread) {
this.invokeSubscriber(subscription, event);
} else {
this.mainThreadPoster.enqueue(subscription, event);
}
break;
case 3:
if(isMainThread) {
this.backgroundPoster.enqueue(subscription, event);
} else {
this.invokeSubscriber(subscription, event);
}
break;
case 4:
this.asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
//通过反射调用了订阅者的订阅函数并把event对象作为参数传入
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, new Object[]{event});
} catch (InvocationTargetException var4) {
this.handleSubscriberException(subscription, event, var4.getCause());
} catch (IllegalAccessException var5) {
throw new IllegalStateException("Unexpected exception", var5);
}
}
ThreadMode共有四类:
post()整体流程图如下
解除注册只要调用unregister()方法即可实现
public synchronized void unregister(Object subscriber) {
//通过typesBySubscriber来取出这个subscriber订阅者订阅的事件类型,
List subscribedTypes = (List)this.typesBySubscriber.get(subscriber);
if(subscribedTypes != null) {
//如果不是null
Iterator var3 = subscribedTypes.iterator();
while(var3.hasNext()) {
Class eventType = (Class)var3.next();
//分别解除每个订阅了的事件类型
this.unsubscribeByEventType(subscriber, eventType);
}
this.typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
private void unsubscribeByEventType(Object subscriber, Class> eventType) {
List subscriptions = (List)this.subscriptionsByEventType.get(eventType);
//subscriptionsByEventType里拿出这个事件类型的订阅者列表.
if(subscriptions != null) {
int size = subscriptions.size();
for(int i = 0; i < size; ++i) {
//分别取消订阅
Subscription subscription = (Subscription)subscriptions.get(i);
if(subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
--i;
--size;
}
}
}
}
从上面代码可以看出最终从typesBySubscriber和subscriptions里分别移除订阅者以及相关信息,完成反注册.
EventBus3.0jar包下载地址