一、简介
EvenetBus是一种发布-订阅事件总线.代码简洁,开销小,并很好的实现了发送者和接收者的解耦.(是一种观察者模式)
二、用到的设计模式
1、单例模式:一个类有且仅有一个实例,并且自行实例化向整个系统提供。
2、建造者模式:将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。使用Builder
3、观察者模式:定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
三、基本使用
1、添加依赖
compile 'org.greenrobot:eventbus:3.1.1'
2、注册事件
public class TestEvent {
private String test;
public MessageEvent(String test){
this.test = test;
}
public String getTest(){
return test;
}
}
3、接受消息
<1> 注册订阅者
EventBus.getDefault().register(this);
<2> 订阅方法,当接收到事件的时候,会调用该方法
//接受普通消息
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(TestEvent testEvent){
Toast.makeText(ViewPageStep1Activity.this, testEvent.getTest(), Toast.LENGTH_SHORT).show();
}
//接受粘性消息
@Subscribe(threadMode = ThreadMode.MAIN,sticky = true)
public void onEventSticky(TestEvent testEvent){
Toast.makeText(ViewPageStep1Activity.this, testEvent.getTest(), Toast.LENGTH_SHORT).show();
}
<3> 解除注册
EventBus.getDefault().unregister(this);
4、发送消息
//普通消息
EventBus.getDefault().post(new TestEvent("我是普通消息"));
//粘性消息
EventBus.getDefault().postSticky(new TestEvent("我是普通消息"));
5、ThreadMode介绍
是一个枚举类,包含四个值:
<1> POSTING
默认的模式,开销最小的模式,订阅者会在发布的同一个线程调用,发布者和订阅者在线程同一线程,避免了线程切换。
<2> MAIN
无论发布者是在主线程中还是在那一条子线程中发布消息,订阅者接收的都在主线程中
如果发布者在主线程发送消息,订阅者就在主线程去接受消息。
如果发布者在子线程发送消息,订阅者就在主线程去接受消息。
<3> BACKGROUND
无论发布者是在主线程或者是那一条子线程中发布消息,订阅者接收的肯定是在子线程中
如果发布者在主线程发送消息,订阅者就会去开启一个新的线程去接受消息。
如果发布者在子线程发送消息,订阅者就会在该同一子线程去接受消息。
<4> ASYNC
在子线程调用,总是开启一个新的线程来调用,适用于做耗时任务,比如数据库操作,网络请求等.
如果发布者在主线程发送消息,订阅者就会去开启一个新的线程去接受消息。
如果发布者在子线程发送消息,订阅者就会去开启一个新的线程去接受消息。
四、源码解析
1、初始化EventBus对象
根据EventBus的使用,可以从getDefault()方法入手。
static volatile EventBus defaultInstance;
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
getDefault()使用“双重校验锁”的单例模式来构建对象。并且使用volatile关键字修饰defaultInstance
接下来看一下构造方法:
public EventBus() {
this(DEFAULT_BUILDER);
}
EventBus(EventBusBuilder builder) {
//以事件类型(消息的对象)为key,subscription订阅者的封装类(订阅者和订阅方法)的集合为value
subscriptionsByEventType = new HashMap<>();
//以订阅者为key,事件类型(消息的对象)的集合为value。主要用于注销时使用
typesBySubscriber = new HashMap<>();
//粘性事件的Map集合
stickyEvents = new ConcurrentHashMap<>();
//自定义handler对象,处理异步线程消息
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
//自定义Runnable对象
backgroundPoster = new BackgroundPoster(this);
//自定义Runnable对象
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线程池对象
executorService = builder.executorService;
}
可以看到构造方法是public,这说明EventBus并不是一个真正的单例类,允许实例化多个EventBus的对象。这样就可以根据需求定制EventBus。这里使用了经典的建造者(Builder)模式,构建一个EventBusBuilder对象。
构造方法里面会初始化一些基础变量。
2、注册register(this);
//使用反射获取注解方法
public void register(Object subscriber) {
//得到订阅者的类的calss对象
Class<?> subscriberClass = subscriber.getClass();
//通过Class得到所有注解的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
//循环所有的注解方法,进行注册
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}
SubscriberMethod将标有注解的方法进行封装:
包含Method(方法)、ThreadMode、Class<?>(方法的参数类型)、priority(优先级)、sticky(是否粘性)
<1> findSubscriberMethods()查找所有的注解方法
//通过Class得到所有注解的方法,subscriberMethodFinder在构造方法中初始化
subscriberMethodFinder.findSubscriberMethods(subscriberClass);
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//从缓存中获取注解方法 METHOD_CACHE是Map,订阅者Class对象为Key,注解方法集合为value
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
//判断缓存中是否有注解方法,有就返回
if (subscriberMethods != null) {
return subscriberMethods;
}
//ignoreGeneratedIndex标志,可以在builder中设置,默认false。
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<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//通过调用prepareFindState方法来获取FindState对象
FindState findState = prepareFindState();
//初始化findState对象
findState.initForSubscriber(subscriberClass);
//循环判断findState.clazz是否为空
while (findState.clazz != null) {
//通过findState对象获取保存的subscriberInfo信息
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();
}
//获取注解方法集合并释放findState
return getMethodsAndRelease(findState);
}
FindState对象就是用来临时存储当前查找状态的。
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();
}
FIND_STATE_POOL是一个FindState类型数组,数组大小为4,用来作为FindState对象的缓存。循环遍历数组,如果FindState不为空,就将对象返回,否则就new一个新的对象并返回。
static class FindState {
//所有注解方法的集合
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
//这两个map是用于判断二次判断订阅者是否已经存在过
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
final StringBuilder methodKeyBuilder = new StringBuilder(128);
Class<?> subscriberClass;
Class<?> clazz;
boolean skipSuperClasses;
SubscriberInfo subscriberInfo;
void initForSubscriber(Class<?> subscriberClass) {
//将订阅者Class对象赋值给clazz变量
this.subscriberClass = clazz = subscriberClass;
//是否去父类中
skipSuperClasses = false;
//SubscriberInfo是一个接口,是一个空值
subscriberInfo = null;
}
//释放变量
void recycle() {
subscriberMethods.clear();
anyMethodByEventType.clear();
subscriberClassByMethodKey.clear();
methodKeyBuilder.setLength(0);
subscriberClass = null;
clazz = null;
skipSuperClasses = false;
subscriberInfo = null;
}
//双重检验
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.
//将参数类型与方法添加到map中返回上一次put的value对象
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);
}
}
//二次校验
private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
//使用方法名和eventType名生成一个签名
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
//通过方法获取当前方法所在的Class对象
Class<?> methodClass = method.getDeclaringClass();
//通过方法签名获取上一次保存的Class对象
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
//校验上次保存的Class==null 或者 上次保存的Class对象是否是当前Class对象的父类
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;
}
}
//获取父类Class对象
void moveToSuperclass() {
if (skipSuperClasses) {
clazz = null;
} else {
clazz = clazz.getSuperclass();
String clazzName = clazz.getName();
/** Skip system classes, this just degrades performance. */
//如果父类为系统类,那么就将clazz设为null
if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) {
clazz = null;
}
}
}
}
<1> FindState类中clazz变量在findUsingInfo中用于判断
<2> FindState类中subscriberInfo变量初始化的时候设置为null,这样在findUsingInfo的判断中就会直接去调用findUsingReflectionInSingleClass()方法去反射获取注解的方法。
<3> 双重校验的目的是
如果只有一个注解方法,就返回true
如果校验方法名不同,参数相同的情况或子类和父类有相同方法的情况
注:小知识 Map.put()方法返回的是上一个value的值,如果之前的key不存在就返回null
看完涉及到FindState的代码,再一次回到findUsingInfo方法,接下来就是调用findUsingReflectionInSingleClass方法。
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
// This is faster than getMethods, especially when subscribers are fat classes like Activities
//获取订阅类中的所有方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
// Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
//循环这些方法
for (Method method : methods) {
//获取方法的修饰符
int modifiers = method.getModifiers();
//判断方法是否是Public
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
//如果是的话,就获取方法的参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
//判断参数的长度
if (parameterTypes.length == 1) {
//获取方法的注解Subscribe(Subscribe就是EventBus自定义的注解类)
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
//如果注解不等于null
if (subscribeAnnotation != null) {
//获取参数类。由于就一个参数,直接就拿到这个参数
Class<?> eventType = parameterTypes[0];
//这里调用findState.checkAdd方法去校验
if (findState.checkAdd(method, eventType)) {
ThreadMode threadMode = subscribeAnnotation.threadMode();
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (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");
}
}
}
<1> findUsingReflectionInSingleClass核心的方法使用反射去获取带有注解的方法
<2> 首先会从findState.clazz保存的订阅类中获取所有的方法
<3> 然后会判断方法是不是public,如果是就继续去寻找,剔除非public方法
<4> 进入判断体中后先回去判断方法参数的个数,如果是1,就继续寻找,不是就剔除。由此可以看到在使用EventBus去收发消息是参数对象只能是1个,如果有多个参数那么就要将这些参数封装为一个对象,再传递。
<5> 调用findState.checkAdd方法去校验,如果true,就将方法、参数类的Class、threadMode、优先级、粘性封装成一个对象,并添加到findState的subscriberMethods集合中。这样就将一个类中所有的注解方法保存起来了。
再次回到findUsingInfo方法,找到一个类的所有注解方法后,接下来就会去该类的父类中去寻找。在findUsingInfo方法调用findState.moveToSuperclass()方法去获取父类的Class对象。
等所有的注解方法找到后就会去调用getMethodsAndRelease(findState)方法。
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> 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;
}
<1> 将findState中保存的注解方法集合赋值给一个List
<2> 释放findState中的变量
<3> 循环findState的FIND_STATE_POOL复用池,为null的话,就将findState放进去。以便下次使用。
<4> 最后将注解方法的集合返回
至此就将类中的所有注解方法都找到并保存到集合中了。
然后调转回到findSubscriberMethods方法,将集合缓存到map中。然后再跳转回到register注册方法中。
将所有的注解方法循环,调用subscribe()方法。将订阅者和注解方法专递过去
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//获取到注解方法的参数的Class对象(即做参数事件类型)
Class<?> eventType = subscriberMethod.eventType;
//将订阅者和注解方法封装成对象(即做订阅)
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//通过参数的事件类型从subscriptionsByEventTypeMap中获取所有的订阅
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
//如果没有订阅,就将新订阅添加进map中
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
//如果之前有订阅,就抛出异常
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
//根据注解方法的优先级添加订阅
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;
}
}
//根据当前的订阅者,获取注解方法的参数的Class对象
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
//如果没有就将参数的Class对象添加到map中
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<Class>).
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, 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);
}
}
}
<1> 从上面的注释可以看出,注册最终就是将订阅和参数Class添加到map中
<2> subscriptionsByEventType这个map是以参数Class对象为key,订阅(订阅者和注解方法)为value,用于发送消息的时候根据参数的Class对象来获取对应的订阅信息,调用其中的注解方法。
<3> typesBySubscriber是以订阅者为key,参数Class对象为value,主要是用于注销时使用。 通过当前的订阅者获取到对应的参数的Class对象,然后使用参数的Class对象来获取到subscriptionsByEventType中的订阅信息,最后将这两个map中的数据全部移除,释放内存。
这样整个注册的过程就完了,主要是用到反射去获取所有的注解方法,最后将其保存在map中。
3、发送消息post(new TestEvent(“我是普通消息”));
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
//将事件保存到事件对列中
eventQueue.add(event);
//判断是否正在post
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()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
<1> currentPostingThreadState是ThreadLocal。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
<2> PostingThreadState封装了一些事件发送中过程所需的数据变量
final static class PostingThreadState {
//事件队列
final List<Object> eventQueue = new ArrayList<Object>();
//是否正在post。默认是false
boolean isPosting;
//是否主线程
boolean isMainThread;
//订阅
Subscription subscription;
//事件
Object event;
boolean canceled;
}
<3> 拿到当前线程的PostingThreadState对象后,将发送的事件保存到事件队列中。
<4> 循环队列调用postSingleEvent方法将事件和PostingThreadState对象传递过去。
进入postSingleEvent(eventQueue.remove(0), postingState)方法
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
//获取事件的Class对象
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
//builder中设置,默认true
if (eventInheritance) {
//获取到所有事件包括父类和实现的
List<Class<?>> 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) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
<1> 这个方法主要就是通过传入的event,获取所有的事件包括父类和实现的
<2> 获取成功就调用postSingleEventForEventType去发送消息
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//获取所有的订阅
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
//取消的标志,值是由postingState.canceled赋予。调用取消方法时会设置为true
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;
}
<1> 根据发送的事件的Class对象获取到之前注册时保存在subscriptionsByEventType这个map中的订阅(订阅者和注解方法)
<2> 获取到之后就去循环所有的订阅,调用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 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);
}
}
<1> 根据设置的不同的ThreadMode执行不同分支
<2> 从上面的代码中就可以看到:
POSTING:不管发送是在哪个线程,都会直接去发送消息
MAIN:会判断发送是否是在主线程,如果是就直接发送消息,否则就使用Handler去切换到主线程再发送消息
BACKGROUND:会判断发送是否是在主线程,如果是就会使用ExecutorService去开启一个子线程去发送消息,否则就直接发送消息
ASYNC:不管发送是在哪个线程,都会使用ExecutorService去开启一个新的子线程去发送消息
<3> 分发器:
mainThreadPoster:是HandlerPoster的实例,继承了Handler,调用enqueue方法
queue = new PendingPostQueue();
void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
<1> 通过调用obtainPendingPost方法获取PendingPost对象
<2> 调用queue.enqueue将pendingPost对象保存到PendingPostQueue中
<3> 发送消息sendMessage给主线程,使用handler的方法将线程切换到主线程中
消息发送完成后就会在handleMessage中接受消息。
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
//开启一个循环
while (true) {
//从PendingPostQueue中获取保存的PendingPost对象
PendingPost pendingPost = queue.poll();
//判断PendingPost对象是否为null
if (pendingPost == null) {
synchronized (this) {
// 再次检查一遍
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
//跳出handleMessage方法,结束循环
return;
}
}
}
//不等于null就调用eventBus.invokeSubscriber方法将pendingPost对象发送去反射使用
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
//如果在规定的时间内还没有处理完毕,则继续回调handleMessage处理,防止队列过长或者事件耗时较长时,while循环阻塞主线程造成卡顿
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
backgroundPoster:
BackgroundPoster实现了Runnable接口,使用ExecutorService开启一个线程去执行
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
eventBus.getExecutorService().execute(this);
}
}
}
<1> 也是使用PendingPost和queue去保存数据
<2> eventBus.getExecutorService().execute(this)去开启一个子线程去执行
<3> executorRunning保证事件是顺序执行。
开启线程后就会去run方法中执行
@Override
public void run() {
try {
try {
//开启循环
while (true) {
//获取PendingPost对象
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
run方法里面也是通过循环取出队列中的任务执行,然后调用eventBus.invokeSubscriber(pendingPost)去执行异步任务。
asyncPoster:
BackgroundPoster实现了Runnable接口,使用ExecutorService开启一个线程去执行
public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
eventBus.getExecutorService().execute(this);
}
和BackgroundPoster不同的是里面没有同步代码块,每次来一个任务都会调用执行,也就是说没执行一个任务都会开一个子线程
@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}
在这三个线程分配类中都用到了PendingPost和PendingPostQueue对象
<1> PendingPost就是将subscription, event进行封装,内部维护了一个List的pendingPostPool复用池,存放PendingPost。包含了两个方法obtainPendingPost以及releasePendingPost
obtainPendingPost
获取PendingPost对象,如果pendingPostPool复用池中有就直接获取,没有就new一个PendingPost对象
releasePendingPost
用于释放PendingPost对象,并将空的PendingPost对象放到pendingPostPool复用池。
<2> PendingPostQueue在handler初始化的时候创建,维护了一个PendingPost对象的链表结构
调用 queue.enqueue就将 PendingPost保存到链表中
synchronized void enqueue(PendingPost pendingPost) {
if (pendingPost == null) {
throw new NullPointerException("null cannot be enqueued");
}
if (tail != null) {
tail.next = pendingPost;
tail = pendingPost;
} else if (head == null) {
head = tail = pendingPost;
} else {
throw new IllegalStateException("Head present, but no tail");
}
//pendingPost保存到链表后就发送通知
notifyAll();
}
调用 queue.poll就将 PendingPost从链表中取出
synchronized PendingPost poll() {
//返回head节点,并将head指针下移
PendingPost pendingPost = head;
if (head != null) {
head = head.next;
if (head == null) {
tail = null;
}
}
return pendingPost;
}
synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
//取PendingPost的时候如果链表为null则wait,等到通知
if (head == null) {
wait(maxMillisToWait);
}
return poll();
}
线程分配完毕后就回调用invokeSubscriber方法去发送消息
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
invokeSubscriber(subscription, event);
}
}
这个方法就是从PendingPost中获取到保存的事件以及订阅对象,
然后就将PendingPost对象释放,调用invokeSubscriber实现消息的发送
void invokeSubscriber(Subscription subscription, Object event) {
try {
subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
} catch (InvocationTargetException e) {
handleSubscriberException(subscription, event, e.getCause());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Unexpected exception", e);
}
}
从订阅中获取到保存的注解方法的Method对象,然后直接调用invoke方法来将事件消息传递过去
整个EventBus就是一个典型的观察者模式的实现。
整个流程就是:
订阅者在注册的时候通过反射的形式将类中的注解方法全部保存到一个map中。
在发送消息的时候根据发送消息的事件类型从map中取出注解方法,然后调用方法,将消息的事件传递给方法。
4、粘性事件
指的就是在发送事件之后再订阅该事件也能收到该事件。
<1> 首先就是先发送事件,粘性事件调用的是postSticky()方法
public void postSticky(Object event) {
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
post(event);
}
这个方法比较简单就是将消息事件,保存到stickyEvents中
stickyEvents是一个map,在EventBus初始化的时候创建。
之后就是调用post()方法和之前一样,由于此时还有注册任何方法,所以是不会去发送消息的。
<2> 然后去注册,注册的时候和之前讲的一样,回到subscribe()方法中
在subscribe()是将找到的注解方法放到map中,最后有一个粘性事件的判断
if (subscriberMethod.sticky) {
//默认是true,builder中设置
if (eventInheritance) {
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, 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);
}
}
如果方法中的粘性变量sticky为true的话,就会去循环在发送粘性事件中保存的stickyEvents中的数据,
取出里面的消息事件。调用checkPostStickyEventToSubscription方法。
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
}
}
这个方法就直接去调用上面发送普通消息的postToSubscription方法去发送消息。
这样就实现了消息的粘性,先发布消息,然后在去订阅获取消息。
5、注销
在不使用EventBus的时候,需要去释放掉内存
调用unregister()方法.
unregister方法中的参数是之前注册的订阅者。
public synchronized void unregister(Object subscriber) {
List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
if (subscribedTypes != null) {
for (Class<?> eventType : subscribedTypes) {
unsubscribeByEventType(subscriber, eventType);
}
typesBySubscriber.remove(subscriber);
} else {
Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
<1> typesBySubscriber就是在之前注册的时候保存的map,是以订阅者为key,消息事件为value
<2> 通过订阅者获取所有的消息事件的集合。然后循环所有的消息事件,调用unsubscribeByEventType方法
private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions != null) {
int size = subscriptions.size();
for (int i = 0; i < size; i++) {
Subscription subscription = subscriptions.get(i);
//判断保存在map中的订阅者是否和注销时传过来的订阅者一致
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}
<1> subscriptionsByEventType就是注册时保存所有的订阅map,以消息事件为key,所有的订阅为value
<2> 根据消息事件,拿到所有的订阅,判断保存在map中的订阅者是否和注销时传过来的订阅者一致,一致的话就从订阅集合中将这个订阅移除掉。订阅集合所有匹配移除完成后,返回到unregister方法中,就会执行typesBySubscriber.remove(subscriber);移除typesBySubscriber中的数据。