您的位置:首页 > 移动开发 > Android开发

Android EventBus 源码解析

2017-12-04 17:59 337 查看
EventBus,由greenrobot组织贡献(该组织还贡献了greenDAO),一个Android事件发布/订阅轻量级框架;

进程内EventBus可以代替Android传统的Intent,Handler,Broadcast或接口函数,在Fragment,Activity,Service线程之间传递数据,执行方法;

github地址  https://github.com/greenrobot/EventBus    点击打开链接

在没有它之前,进程内通信一直都是用的广播来发送接收消息,后来用了后发现真的是太方便了,而且还是轻量级的,最近研究了下它的源码,

学习了下大神牛逼的架构和思维,确实很厉害,为啥我没想到呢。

怎么使用的就不做介绍了,相信大家都会用,下面直接进入正文

先看下源码结构,如图:



代码量其实不是很多,很多类里面就只有一点代码,前面3个文件目录都是一些辅助工具类,不是核心,有空可以去学习下,

这里只解析主干逻辑。

平时我们主要用这几个方法:注册订阅者,注销订阅者,定义订阅方法,post事件,所以就从这几个方面开始解析

首先我们知道EventBus用的是单例模式,整个进程中只会有一个EventBus的实例

static volatile EventBus defaultInstance;

/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}


这里加上同步,防止多线程调用getDefault()时出现几个实例

接下来看下定义订阅方法

@Subscribe(threadMode = ThreadMode.MAIN)
public void refreshUI(RefreshBagEvent event) {

}

@Subscribe
public void loadData(DataChangeEvent event) {

}


平时就是这么定义的订阅方法,为啥要这么写呢,我们先看下这个注解@Subscribe

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
/**
* 指定订阅方法所在线程
* @return
*/
ThreadMode threadMode() default ThreadMode.POSTING;

/**
* 是否开启粘性事件
* If true, delivers the most recent sticky event (posted with
* {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
*/
boolean sticky() default false;

/**
* 优先级
* Subscriber priority to influence the order of event delivery.
* Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
* others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
* delivery among subscribers with different {@link ThreadMode}s! */
int priority() default 0;

}


这个定义的注解包含了3个方法,都有默认值,订阅方法所在线程、是否开启粘性事件模式、优先级

为啥要定义这么一个注解呢?

问题先放这,后面揭晓,接下来看下注册订阅者方法register()

/**
* 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<?> subscriberClass = subscriber.getClass();
// 获取订阅者订阅的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
// 加上同步block,可能同时有多处都在注册
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}


当前订阅者register传入进来,拿到它的Class对象,根据这个Class对象获取register的订阅方法,看下这些订阅方法如何被获取的

private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();


List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
List<SubscriberMethod> 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;
}
}


可以看到调用了findUsingReflection()或者findUsingInfo(),ignoreGeneratedIndex默认是false,那么就会直接调用findUsingReflection(),继续往下看

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
findState.subscriberInfo = getSubscriberInfo(findState);
// 这里应该是从缓存中获取订阅的方法,不过看源码findState.subscriberInfo永远都是null,所以进不去
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 {
// 利用反射获取订阅方法储存在findState里面
findUsingReflectionInSingleClass(findState);
}
findState.moveToSuperclass();
}
// 从findState中获取订阅方法
return getMethodsAndRelease(findState);
}

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 subscribeAnnotation = method.getAnnotation(Subscribe.class);
// 方法中Subscribe注解不为null
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
// 检查findState是否添加过这个订阅方法
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)) {
// 抛出异常,订阅的方法必须是public,不带static、abstract的
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}


findUsingReflectionInSingleClass()反射获取订阅方法,看到这知道为啥要用注解@Subcribe了吧,因为一个类那么多方法,怎么知道哪些方法是订阅方法呢,就是用这个注解作为标识

private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
// 回收findState的数据
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;
}


到这里,这个订阅者的方法都以List的形式返回了,接着回到register()

public void register(Object subscriber) {
Class<?> subscriberClass = subscriber.getClass();
// 获取订阅者订阅的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
// 加上同步block,可能同时有多处都在注册
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
subscribe(subscriber, subscriberMethod);
}
}
}


接下来就是开始循环把这些订阅方法一个一个的注册了,看下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);
// 根据事件类型获取订阅实体集合,CopyOnWriteArrayList是线程安全的
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
if (subscriptions == null) {
// 如果subscriptionsByEventType还没有事件.class对象eventType相关的订阅实体集合,就new 一个
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {
// 如果subscriptionsByEventType有eventType相关的订阅实体集合,且包含newSubscription,抛出异常已经注册过了
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}

// 把newSubscription添加到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;
}
}

// typesBySubscriber用于判断是否注册过某个订阅者
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);

// sticky默认false
if (subscriberMethod.sticky) {
// eventInheritance 默认为true
// 如果eventType代表的类或者接口是candidateEventType代表的类或者接口或者父类父接口,也要post事件
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);
}
}
}


这个方法还挺长的,解析我都写在代码里面了,逻辑还是挺复杂的

/**
* 储存事件及父类父接口Class对象;
* key:事件Class对象,value:事件及父类父接口Class对象
*/
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();

/**
* 储存事件及对应方法;
* key是事件的Class对象,value是订阅者及订阅的方法集合
*/
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
/**
* 储存订阅者及事件Class对象;
* 用于判断订阅者是否注册过
*/
private final Map<Object, List<Class<?>>> typesBySubscriber;
/**
* 存储粘性事件;
* 用于postSticky()
*/
private final Map<Class<?>, Object> stickyEvents;

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
// 初始化一个PostingThreadState对象
return new PostingThreadState();
}
};


跟EventBus这个类的这几个成员变量有关,这几个集合的作用主要是用来存储,具体什么作用我都解释了,这个订阅方法的核心

把事件和订阅者相关的方法存储在subscriptionsByEventType 里面,因为一个事件可能在很多地方都注册过,最后还有一个粘性事件

sticky的处理,什么是粘性事件,比如这个事件在A页面发送完毕了,一般情况下注册过的地方就会马上接受到这个事件处理掉,

然后打开过注册了这个事件的B页面的时候,是不会再接受到这个事件的,而粘性事件就相反,打开B页面同样会接受到这个事件,

可以看下源码

// sticky默认false
if (subscriberMethod.sticky) {
// eventInheritance 默认为true
// 如果eventType代表的类或者接口是candidateEventType代表的类或者接口或者父类父接口,也要post事件
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);
}
}
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
// If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
// --> Strange corner case, which we don't take care of here.
postToSubscription(newSubscription, stickyEvent, isMainThread());
}
}


这里才刚开始注册事件,就调用了postToSubscription()去发布事件,postToSubscription()就是post事件的方法,这个方法后面会讲到,到这里注册就算解析完了,估计客观们都晕了,哈哈,我就用一句话概括下:
注册事件其实就是用一个HashMap   subscriptionsByEventType 把事件和注册了事件相关的类和方法储存起来,方便后面post(事件)使用。

接下来看下post()方法,

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
// 初始化一个PostingThreadState对象
return new PostingThreadState();
}
};


/** Posts the given event to the event bus. */
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
// 添加事件event对象
eventQueue.add(event);

// 状态是否为posting,如果没有,则开启
if (!postingState.isPosting) {
// 当前线程是否是主线程
postingState.isMainThread = isMainThread();
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
// 循环开始post事件,每post一个事件,就从eventQueue中移除一个事件对象
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
// 最终恢复默认值
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}

TheadLocal不是很清楚的小伙伴可以移步到这,

ThreadLocal源码解析
http://blog.csdn.net/msn465780/article/details/78673656   点击打开链接

/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
final List<Object> eventQueue = new ArrayList<>();
boolean isPosting;
boolean isMainThread;
Subscription subscription;
Object event;
boolean canceled;
}


PostingTheadState是一个静态类内部太监类,说白了就是一个实体,用来存储当前线程和post事件的一些状态。
一开始是存储post的事件,因为可能有很多地方都在post,接下来循环调用postSingleEvent(),

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
// eventInheritance默认为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) {
// post事件,但是没有地方注册就打印出提示日志
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
// 不知道为啥还要执行以下代码,既然没有注册这个事件还去post一个未被注册的新事件,不是形成了递归吗?
post(new NoSubscriberEvent(this, event));
}
}
}


代码核心是调用postSingleEventForEventType()

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
// 从储存regist的方法中获取事件对应的方法
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
// 开始循环把同一个事件post到注册者,意思就是调用这个事件订阅的方法
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;
}


哈哈,看到了吧,根据事件的Class对象subscriptionsByEventType.get(eventClass) 获取到相关的订阅者和方法,subscriptionsByEventType 还熟悉吗?就是register的时候用来保存的那个HashMap,那到这个方法后干啥呢?调用
postToSubscription(),这个方法还熟悉吗?前面粘性事件Sticky中提到过,就是用的它,是它是它就是它!

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {
// 如果post()在主线程,则立即反射调用订阅方法
invokeSubscriber(subscription, event);
} else {
// 否认,加入UI线程消息队列末尾
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) {
// 如果post()的线程为UI线程,则在线程池中反射调用订阅方法
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);
}
}

switch语句根据订阅方法的时候,注解中指定线程,分别post事件,一个一个的讲下为啥这么区分,先看下都用到的方法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(),是一种反射机制,参数中知道了订阅者对象,订阅者方法的事件参数对象,那么就可以直接调用到这个订阅方法了,也就达到发送事件接受到事件的循环了。

POSTING 

未指定订阅方法线程的时候默认值,直接调用,post在哪个线程,这个订阅方法就在哪个线程

MAIN           

指定订阅方法在UI线程中执行,如果当前为UI线程直接调用,否则利用MainThreadSupport对象加入UI线程消息队列                               末尾执行,MainThreadSupport其实就是主线程的Handler对象,后面再讲

MAIN_ORDERED   

这个和MAIN有啥区别呢?其实区别就是如果MainThreadSupport存在会优先加入UI线程消息队列末尾,否则才是立即执行

BACKGROUND

如果当前为主线程,加入后台线程执行,否则立即执行

ASYNC

不管当前什么线程,都在后台执行

post主干逻辑基本都说完了,再说下刚才那几个poster,MainThreadSupport、BackgroundPoster、AsyncPoster

他们都是接口,继承于Poster。

MainThreadSupport

public class HandlerPoster extends Handler implements Poster {

private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;

protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
// 创建一个自定义的队列
queue = new PendingPostQueue();
}

public void enqueue(Subscription subscription, Object event) {

// 获取存储pendingPost  list中最末一个
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
// 获取到的pendingPost 入队
queue.enqueue(pendingPost);
// 当前handler对象是否还活动,如果没有活动就让它活动起来,这里的代码就相当于启动handler的作用
// 让handler处于发送、接受消息的循环中
if (!handlerActive) {
handlerActive = true;
// 发送空消息,在消息队列末尾,就会执行下面的handleMessage(),如果发送消息未成功,抛出异常
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}

@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
// 获取手机开机到现在的时间(毫秒),不包含睡眠时间
long started = SystemClock.uptimeMillis();
// 开启一个循环
while (true) {
// 获取队列头部的pendingPost
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
// 继续获取剩下队列头部的pendingPost
pendingPost = queue.poll();
if (pendingPost == null) {
// 如果获取了两次都是null,那么handlerActive = false;跳出方法
handlerActive = false;
return;
}
}
}
// 通过反射调用订阅者对象的订阅方法
eventBus.invokeSubscriber(pendingPost);
// 计算反射调用这个订阅方法的执行耗费时间(毫秒)
long timeInMethod = SystemClock.uptimeMillis() - started;
// 默认最大调用时间间隔是10毫秒,如果小于就继续循环从队列中取订阅方法反射调用,
// 如果大于就把剩下需要调用的加入消息队列末尾,然后又来执行handleMessage(),
// 因为这是在UI线程中进行的,如果调用时间过长,很容易出现ANR,所以把剩下没
// 调用完的加入消息队列末尾,让UI的其他操作先执行,防止阻塞
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
// 因为已经加入了队列末尾,所有这个方法没有作用了可以退出去了
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
}

作用就是把post加入到UI线程消息队列末尾执行

BackgroundPoster

final class BackgroundPoster implements Runnable, Poster {

private final PendingPostQueue queue;
private final EventBus eventBus;

private volatile boolean executorRunning;

BackgroundPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}

public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
// 线程池是否活跃中,如果没有,则开启
if (!executorRunning) {
executorRunning = true;
// 把当前BackgroundPoster对象放入线程池中并执行
eventBus.getExecutorService().execute(this);
}
}
}

@Override
public void run() {
try {
try {
while (true) {
// 从PendingPostQueue中取头部PendingPost,如果取两次都为null,退出方法
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) {
eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}

}


创建了一个线程池,然后在后台中执行

AsyncPoster

class AsyncPoster implements Runnable, Poster {

private final PendingPostQueue queue;
private final EventBus eventBus;

AsyncPoster(EventBus eventBus) {
this.eventBus = eventBus;
queue = new PendingPostQueue();
}

public void enqueue(Subscription subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
queue.enqueue(pendingPost);
eventBus.getExecutorService().execute(this);
}

@Override
public void run() {
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
eventBus.invokeSubscriber(pendingPost);
}

}

跟BackgroundPoster相似

接下来看下注销事件

我们安卓中一般都会在Activity或者Fragment注册事件,如果不注销肯定会发生内存泄漏,导致内存溢出,

unregister()

/**
* 储存事件及对应方法;
* key是事件的Class对象,value是订阅者及订阅的方法集合
*/
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
/**
* 储存订阅者及事件Class对象;
* 用于判断订阅者是否注册过
*/
private final Map<Object, List<Class<?>>> typesBySubscriber;


/** Unregisters the given subscriber from all event classes. */
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 {
logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
}
}
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
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);
if (subscription.subscriber == subscriber) {
subscription.active = false;
subscriptions.remove(i);
i--;
size--;
}
}
}
}

其实我都不用解析了,还记得开始我提到过EventBus有几个成员变量,都是容器类,typesBySubscriber用于判断是否注册过,

subscriptionsByEventType这个很多地方都出现过,保存事件及对应订阅方法的,注销其实就是把这个订阅者和相关方法移除掉,

哈哈,是不是想到判断当前是否注册过的那个方法了,看下源码

public synchronized boolean isRegistered(Object subscriber) {
return typesBySubscriber.containsKey(subscriber);
}


明白了吧!

到这里EventBus这个优秀的框架主干都解析完了,我可能很多地方没描述清楚,不过小伙伴们懂逻辑原理就行了,细微的方法可以下面慢慢看下了。

EventBus说白了就是根据注解把相关的方法都保存在一个HashMap里面,key为事件Class对象,value为订阅者及相关订阅方法的集合,发送事件的时候就根据这个事件的Class对象从HashMap中拿出来一个一个循环的反射调用订阅者的订阅方法。

好了,又可以愉快玩耍了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息