EventBus是一个用于简化Andorid、Fragment、Threads、Service之间信息传递的一个发布/订阅事件集。
使用EventBus的建议:
compile 'org.greenrobot:eventbus:3.1.1'
public class MessageEvent {
}
EventBus.getDefault().register(this);
@Subscribe(threadMode = ThreadMode.MAIN, sticky = false, priority = 0)
public void handleData(MessageEvent mMessageEvent) {
}
3.0版本以后可以随便定义方法名,但需要添加一个注解@Subscribe,并且要指定线程模型,如果没有添加,那就是默认为POSTING。
EventBus.getDefault().post(messageEvent);
EventBus.getDefault().unregister(this);
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
ThreadMode threadMode() default ThreadMode.POSTING;
/**
如果为true,Sticky事件只指事件消费者在事件发布之后才注册的也能接收到该事件的特殊类型。Android中就有这样的实例,也就是Sticky Broadcast,即粘性广播。正常情况下如果发送者发送了某个广播,而接收者在这个广播发送后才注册自己的Receiver,这时接收者便 无法接收到刚才的广播,为此Android引入了StickyBroadcast,在广播发送结束后会保存刚刚发送的广播(Intent),这样当接收者注册完Receiver 后就可以接收到刚才已经发布的广播。这就使得我们可以预先处理一些事件,让有消费者时再把这些事件投递给消费者。
*/
boolean sticky() default false;
/**
最后一个参数是priority,Method的优先级,优先级高的可以先获得分发的事件。这个不会影响不同的ThreadMode的分发事件顺序。
*/
int priority() default 0;
}
1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;
3、RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
这3个生命周期分别对应于:Java源文件(.java文件) —> .class文件 —> 内存中的字节码。
那怎么来选择合适的注解生命周期呢?
首先要明确生命周期长度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。
@Target({ElementType.METHOD}) 表示适用于方法 。
ThreadMode 是enum(枚举)类型,threadMode默认值是POSTING。ThreadMode有四种模式:
public enum ThreadMode {
/**
事件的处理在和事件的发送在相同的进程,Subscriber会在post event的所在线程回调,故它不需要切换线程来分发事件,因此开销最小。它要求task完成的要快,不能请求MainThread,适用简单的task。
*/
POSTING,
/**
Subscriber会在主线程(有时候也被叫做UI线程)回调,如果post event所在线程是MainThread,则可直接回调。注意不能阻塞主线程。
*/
MAIN,
/**
Subscriber会在主线程(有时候也被叫做UI线程)回调,如果post event所在线程是MainThread,则事件将总是排队等待传递。注意不能阻塞主线程。
*/
MAIN_ORDERED,
/**
Subscriber会在后台线程中回调。如果post event所在线程不是MainThread,那么可直接回调;如果是MainThread,EventBus会用单例background thread来有序地分发事件。注意不能阻塞background thread。
*/
BACKGROUND,
/**
当处理事件的Method是耗时的,需要使用此模式。尽量避免同时触发大量的耗时较长的异步操作,EventBus使用线程池高效的复用已经完成异步操作的线程。
*/
ASYNC
}
static volatile EventBus defaultInstance;
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
单例模式,而且是双重校验的单例,确保在不同线程中也只存在一个EvenBus的实例。
volatile关键字在java并发编程中常用,比synchronized的开销成本要小,轻便。作用是线程能访问共享变量,什么是共享变量呢?共享变量包括所有的实例变量,静态变量和数组元素,他们都存放在堆内存中。
/**
* Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
* central bus, consider {@link #getDefault()}.
*/
public EventBus() {
this(DEFAULT_BUILDER);
}
它的构造方法并没有设置成私有的,注解我们看到,每一个EventBus都是独立地、处理它们自己的事件,因此可以存在多个EventBus,而通过getDefault()方法获取的实例,则是它已经帮我们构建好的EventBus,是单例,无论在什么时候通过这个方法获取的实例都是同一个实例。除此之外,我们可以通过建造者帮我们建造具有不同功能的EventBus。
EventBus(EventBusBuilder builder) {
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
//后面是一些表示开关信息的boolean值以及一个线程池
}
private final Map, CopyOnWriteArrayList> subscriptionsByEventType;
private final Map
public void register(Object subscriber) {
Class> subscriberClass = subscriber.getClass();
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
SubscriberMethodFinder#findSubscriberMethods()方法具体实现:
List findSubscriberMethods(Class> subscriberClass) {
List subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
subscriberMethods = 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.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
findUsingInfo()方法具体实现:
private List findUsingInfo(Class> subscriberClass) {
//后面解释
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//获得订阅者的信息,一开始会返回null
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
//通过反射来查找订阅方法
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
findUsingReflectionInSingleClass方法具体实现(筛选):
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
//调用getDeclaredMethods方法输出的是自身的public、protected、private方法。
// This is faster than getMethods, especially when subscribers are fat classes like Activities
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
Class>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {//表明methods的参数只能有一个
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) {
//SubscriberMethod封装订阅方法
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
}
}
}
}
在这里主要是使用了Java的反射和对注解的解析。首先通过反射来获取订阅者中所有的方法。并根据方法的类型,参数和注解来找到订阅方法。找到订阅方法后将订阅方法相关信息保存到FindState当中。到这里便完成对订阅者中所有订阅方法的查找。
FindState#checkAdd方法返回true的时候,才会把方法保存在findState的subscriberMethods内。而SubscriberMethod则是用于保存订阅方法的一个类。
FindState#checkAdd具体实现:
boolean checkAdd(Method method, Class> eventType) {
// 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
// Usually a subscriber doesn't have methods listening to the same event type.
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
// Paranoia check
throw new IllegalStateException();
}
// Put any non-Method object to "consume" the existing Method
anyMethodByEventType.put(eventType, this);
}
return checkAddWithMethodSignature(method, eventType);
}
}
FindState#checkAddWithMethodSignature()具体实现:
private boolean checkAddWithMethodSignature(Method method, Class> eventType) {
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());
//methodKey由方法名与事件名组成
String methodKey = methodKeyBuilder.toString();
//获取当前方法所在的类的类名
Class> methodClass = method.getDeclaringClass();
Class> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
// Only add if not already found in a sub class
return true;
} else {
// Revert the put, old class is further down the class hierarchy
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
eventType:表示方法的参数类型
该方法首先获取了当前方法的methodKey、methodClass等,并赋值给subscriberClassByMethodKey,如果方法签名相同,那么返回旧值给methodClassOld,接着是一个if判断,判断methodClassOld是否为空,由于第一次调用该方法的时候methodClassOld肯定是null,此时就可以直接返回true了。
再看看methodClassOld.isAssignableFrom(methodClass)这个方法,这个的意思是:methodClassOld是否是methodClass的父类或者同一个类。如果这两个条件都不满足,则会返回false,那么当前方法就不会添加为订阅方法了。
在findUsingReflectionInSingleClass中,经过一系列的对Method遍历,执行findState.subscriberMethods.add(),到这里便完成对订阅者中所有订阅方法的查找。最后会在List
看SubscriberMethodFinder#getMethodsAndRelease方法:
private List getMethodsAndRelease(FindState findState) {
List subscriberMethods = new ArrayList<>(findState.subscriberMethods);
findState.recycle();
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
if (FIND_STATE_POOL[i] == null) {
FIND_STATE_POOL[i] = findState;
break;
}
}
}
return subscriberMethods;
}
从findState获取subscriberMethods,放进新的ArrayList。
SubscriberMethodFinder#prepareFindState方法具体实现:
private FindState prepareFindState() {
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
FIND_STATE_POOL[i] = null;
return state;
}
}
}
return new FindState();
}
这是个复用池。第一次prepareFindState时,FIND_STATE_POOL[i]全不是null,有了一个state之后把相应的FIND_STATE_POOL[i]的引用变为null,这是为了防止并发编程时造成相互干扰。用完了这个state之后,recycle下面的for循环,会找到一个引用为null的FIND_STATE_POOL[i],并把自身引用赋给他。这样在并发的时候,这个复用池的效果就出来了:用的时候隔离开,用完了放回去。
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//获取订阅方法的参数类型(订阅事件)
Class> eventType = subscriberMethod.eventType;
//订阅者和订阅方法 封装成Subscription
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//获取当前订阅事件中Subscription的List集合
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
//如果为null,说明该subscriber尚未注册该事件
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
//订阅者已经注册则抛出EventBusException
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
//根据优先级来设置放进subscriptions的位置,优先级高的会先被通知
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
//根据subscriber(订阅者)来获取它的所有订阅事件
List> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
//下面是对粘性事件的处理
if (subscriberMethod.sticky) {
if (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, Object>> entries = stickyEvents.entrySet();
for (Map.Entry, Object> entry : entries) {
Class> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {
Object stickyEvent = entry.getValue();
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
Subscription一个很重要的封装类:作用主要保存 订阅者和订阅方法
Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
this.subscriber = subscriber;
this.subscriberMethod = subscriberMethod;
active = true;
}
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List
currentPostingThreadState 是一个ThreadLocal变量,即线程本地变量,不同线程之间不会相互影响。
1. 首先获取当前线程的postingState,得到当前线程的消息队列,将当前事件event加入到队列中。
2. 判断是否是在主线程post,设置标志位,调用postSingleEvent进行分发。
EventBus#PostingThreadState 内部类的实现:
final static class PostingThreadState {
final List
该PostingThreadState主要是封装了当前线程的信息,以及订阅者、订阅事件等。
通过currentPostingThreadState.get()来获取PostingThreadState:
private final ThreadLocal currentPostingThreadState = new ThreadLocal() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
EventBus#postSingleEvent 方法:
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
List> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
//如果没找到订阅该事件的订阅者
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
EventBus#postSingleEventForEventType 方法:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class> eventClass) {
CopyOnWriteArrayList subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}
CopyOnWriteArrayList是为了线程安全,每次对List的修改都会重新一份,由于是线程安全的所以不需要同步处理,但是对HashMap的读取操作则不是线程安全的,所以需要线程同步。
1. 首先获取event(订阅事件)映射的subscriptions列表。
2. 遍历subscriptions,将event和subscription(包含订阅者和订阅方法)赋值到postingState对应成员变量中,调用postToSubscription进行分发。
EventBus#postToSubscription 方法:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
在这里取出订阅方法的线程模式,之后根据订阅方法所设置的线程模式来选择线程来执行订阅方法的线程。 isMainThread表示发送Post的线程。
以下根据订阅方法的线程模式分类:
- POSTING:默认的 ThreadMode,表示在执行 Post 操作的线程直接调用订阅者的事件响应方法,
不论该线程是否为主线程(UI 线程)。直接调用invokeSubscriber()。
- MAIN:如果post是在MainThread则直接调用上面的方法;如果不是则向mainThreadPoster加入队列。mainThreadPoster类型是HandlerPoster,其继承自Handler。也即是通过Handler将订阅方法切换到主线程执行。
- BACKGROUND:订阅方法在后台线程,如果Post操作在主线程,则通过backgroundPoster加入队列。
- ASYNC:发布线程是否为主线程,都使用一个空闲线程来处理。不使用队列管理多个事件,也不管发布者处在主线程与否,为每一个事件单独开辟一个线程处理。
public synchronized void unregister(Object subscriber) {
List> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
从事件类型的订阅者集合中移除订阅者
unsubscribeByEventType方法实现:
private void unsubscribeByEventType(Object subscriber, Class> eventType) {
List subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
EventBus用法及源码解析
EventBus 3.0进阶:源码及其设计模式 完全解析
EventBus源码解析
EventBus源码分析(一)
EventBus阅读
EventBus源码解读详细注释