有过Android开发经验的人相信对EventBus应该都有所了解,EventBus是一个开源库,它使用观察者模式对模块间的通信进行解藕。
下面是一个Android中使用EventBus的实例,相信大家都不陌生:
class MainActivity : AppCompatActivity() {
private val TAG = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
EventBus.getDefault().register(this)
event_btn_1.setOnClickListener {
Thread(Runnable { EventBus.getDefault().post(Event(1)) }).start()
}
}
@Subscribe(threadMode = ThreadMode.MAIN_ORDERED)
fun onReceive(event: Event) {
Log.i(TAG, "currentThread: ${Thread.currentThread().name} event = ${event.what}")
}
override fun onDestroy() {
super.onDestroy()
EventBus.getDefault().unregister(this)
}
class Event(var what: Int = 0)
}
可以看到使用在项目中使用EventBus非常简单,主要包括以下几步:
1、在onCreate()方法中注册观察者;
2、定义一个方法,这个方法要使用@Subscribe注解(在上面例子中我们通过threadMode = ThreadMode.MAIN_ORDERED标记了onReceive()方法将在主线程中被调用);
3、在onDestroy()方法中注销观察者(注意:这一点非常重要,如果不注销,就会导致内存泄露)
4、在其他地方调用EventBus的post()方法发送消息。
分析上面的代码和EventBus的使用步骤,我们大概会想到下面几个问题:
1、EventBus是怎么管理观察者的,如果我们在onCreate()方法中调用两次register()方法,当EventBus发送消息是会不会收到两条消息;
2、上面代码中我们使用了EventBus.getDefault()获取了一个EventBus对象,那么我们是不是可以配置适合自己的EventBus对象,EventBus可以进行哪些配置?
3、EventBus中的消息是怎么传递的?
4、EventBus是怎么进行线程切换的?
5、EventBus中有粘性事件,粘性事件是怎么实现的?
基于这几个问题,我们追踪一下EventBus的源码,我们从EventBus.getDefault方法入手。
//这个方法我们的逻辑我们很熟悉,就是一个单例
/** Convenience singleton for apps using a process-wide EventBus instance. */
public static EventBus getDefault() {
EventBus instance = defaultInstance;
if (instance == null) {
synchronized (EventBus.class) {
instance = EventBus.defaultInstance;
if (instance == null) {
instance = EventBus.defaultInstance = new EventBus();
}
}
}
return instance;
}
/**
* 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(EventBusBuilder builder) {
logger = builder.getLogger();
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;
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
//订阅失败时是否抛出异常,默认时false,应当在开发阶段设置为true,以便我们排查问题
throwSubscriberException = builder.throwSubscriberException;
//是否允许事件继承,默认允许,比如事件A继承自事件B,当发送A消息时B的订阅也可以收到消息,如果将这个参数设置为false可以提升事件的发布效率
eventInheritance = builder.eventInheritance;
//自定义线程池
executorService = builder.executorService;
}
上面是getDefault()和EventBus的构造方法,我们可以知道通过getDefault()方法获取到的EventBus对象是一个单例对象。同时在EventBus()构造方法的注释中我们知道,每一个EventBus对象的事件传递都是分开的,如果我们在一个类中用EventBus对象A注册了观察者,要想这个类能收到消息,则必须在其他地方使用A发送消息。
通过EventBus的构造方法我们还可以了解到EventBusBuilder中其实主要加了一些调试EventBus时需要的配置,比如Log,比如订阅失败时是否抛出异常等。当然EventBusBuilder中也有两个主要参数,一个是eventInheritance一个是executorService,这两个参数的含义在上面代码注释中有说明。如果我们一次发送的事件很少,那么修改eventInhericatance并不能显著提高性能,另外设置自定义线程池时我们也要保证自定义的线程池不会被卡住,所以这两项操作也很少使用,所以大部分情况下我们使用默认EventBus对象就好。而且因为每一个EventBus对象的事件传递都是分开的,默认的EventBus对象又是单例的,所以使用默认的EventBus对象避免了将其从一个线程传递到另一个线程。
还有在EventBus的构造方法中我们看到三个消息发布器,分别是mainThreadPoster,backgroundPoster和asyncPoster,此时我们可以猜想,EventBus向不同的线程中发送消息使用的是不同的发布器,到底是不是我们一会验证。
1、订阅者注册
下面我们分析EventBus的register()方法,这个方法用来向EventBus中注册一个观察者,以便该观察者接收EventBus发送的事件。
/**
* Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
* are no longer interested in receiving events.
*
* 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();
//查找当前类subscriber类及其父类中用@Subscribe注解的方法
List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//依次订阅subscriber中用@Subscribe注解的方法
subscribe(subscriber, subscriberMethod);
}
}
}
register()方法的代码比较简单,查找观察者类subscriber中及其父类中所有接收消息的方法(即用@Subscribe注解修饰的方法),用SubscriberMethod类定义,然后依次调用subscribe()方法将subscriber类和SubscriberMethod添加到订阅列表中。查找SubscriberMethod的逻辑在SubscriberMethodFinder.findSubscriberMethods()方法中,查找SubscriberMethod的逻辑有两种一种是缓存中有FindState的索引,就根据索引查找(默认);另一种是无论有没有FindState的索引,都通过反射查找,使用哪种方式可以通过EventBusBuilder.ignoreGeneratedIndex(boolean ignoreGeneratedIndex)方法配置。查找SubscriberMethod的逻辑并不简单,但这不是我们要分析的重点,所以先不看。
这里先看下SubscriberMethod类,以便后面理解subscribe(Object subscriber, SubscriberMethod subscriberMethod)方法。
/** Used internally by EventBus and generated subscriber indexes. */
public class SubscriberMethod {
final Method method;//订阅者中接收消息的方法
final ThreadMode threadMode;//接收消息的方法应该在哪个线程中被调用
final Class> eventType;//消息类型
final int priority;//方法的优先级
final boolean sticky;//方法是否是粘性的,如果是,即使先发送消息,后注册订阅者方法,订阅者也能收到消息
/** Used for efficient comparison */
String methodString;
public SubscriberMethod(Method method, Class> eventType, ThreadMode threadMode, int priority, boolean sticky) {
this.method = method;
this.threadMode = threadMode;
this.eventType = eventType;
this.priority = priority;
this.sticky = sticky;
}
@Override
public boolean equals(Object other) {
......
}
......
@Override
public int hashCode() {
return method.hashCode();
}
}
这个类应该不用多说,下面我们分析subscribe(Object subscriber, SubscriberMethod subscriberMethod)方法:
//这个方法用于将订阅者和订阅方法添加到订阅列表中
// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//获取消息类型
Class> eventType = subscriberMethod.eventType;
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//根据消息类型查找订阅者列表
CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
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();
//根据SubscriberMethod的优先级由高到低,将订阅者插入到订阅者列表
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
subscriptions.add(i, newSubscription);
break;
}
}
//将subscriber中订阅的所有消息类型放到subscribeEvents列表中,然后通过map与subscriber对应起来
List> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
/**
* 如果SubscribeMethod是非粘性的,则订阅操作至此结束,
* 否则,查找EventBus中的粘性消息,发送给订阅者
* */
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).
//stickyEvents是Map类型,这里为了提高遍历速度要先改变一下数据结构为set
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);
}
}
}
//检查粘性事件并发送给订阅者
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());
}
}
通过上面的代码我们发现,EventBus的注册流程并不复杂,就是拿到一个订阅者对象之后查找其接收消息的方法,然后用订阅者对象和接收消息的方法创建一个Subscription对象,并将Subscription对象放到某个消息类型的订阅列表中。同时还用typesBySubscriber记录了某个订阅对象订阅了哪些消息(这个在注销订阅者时会很重要)。最后如果订阅者接收消息的方法还接收粘性事件,就查找粘性事件列表,并把对应类型的粘性事件发送给订阅者。
上面代码中发送事件时调用了postToSubscription()方法,其实所有的事件发送都在这个方法中进行。
2、事件发送
我们知道发送粘性事件调用的是postSticky()方法,而发送非粘性事件是调用post()方法,下面是这两个方法的源码:
/**
* Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky
* event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}.
*/
public void postSticky(Object event) {
//将event存放到stickyEvents中
synchronized (stickyEvents) {
stickyEvents.put(event.getClass(), event);
}
// Should be posted after it is putted, in case the subscriber wants to remove immediately
//调用Post发送事件
post(event);
}
/** Posts the given event to the event bus. */
public void post(Object event) {
//通过currentPostingThreadState获取当前线程中的postingState,currentPostingThreadState是EventBus中ThreadLocal类型的final属性。postingState是通过currentPostingThreadState跟当前线程绑定到一起的。
PostingThreadState postingState = currentPostingThreadState.get();
//获取当前线程中要发送的消息列表
List
在post()方法中通过currentPostingThreadState.get()方法获取了一个PostingThreadState对象,这个对象是跟当前线程绑定在一起的,里面存了要发送的事件列表和用于接收事件的Subscription,类源码如下:
/** For ThreadLocal, much faster to set (and get multiple values). */
final static class PostingThreadState {
final List
获取到PostingThreadState对象之后将要发送的事件添加到PostingThreadState的事件列表中,然后为PostingThreadState标记当前是否在主线程中,最后遍历事件列表依次调用postSingleEvent()方法发送事件。
我们继续追踪postSingleEvent()方法:
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class> eventClass = event.getClass();
boolean subscriptionFound = false;
//如果允许事件继承,就需要找到要发送的事件event的类型,以及它继承的父类和实现的接口的类型,对于所有订阅了这些类型的消息的订阅者都要发送事件
if (eventInheritance) {
//获取事件的类型,这里获取到的除了事件的类本身外还包括该事件继承的类以及实现的接口
List> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class> clazz = eventTypes.get(h);
//调用postSingleEventForEventType方法发送事件
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
//如果不允许事件继承,那么只给订阅了event的订阅者发送事件,对于订阅了event类型父类的订阅者不发送
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));
}
}
}
postSingleEvent()方法调用了postSingleEventForType()方法来执行发送逻辑,postSingleEventForType()方法会返回一个boolean值表示有没有订阅者订阅了这个事件,如果没有订阅者定于这个事件就发送一个NoSubscriberEvent。
我们看下postSingleEventForType()方法的具体逻辑:
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class> eventClass) {
CopyOnWriteArrayList subscriptions;
synchronized (this) {
//通过消息类型找到订阅者列表
subscriptions = subscriptionsByEventType.get(eventClass);
}
//如果订阅者列表不为空,就遍历该列表,调用postToSubscription()方法执行发送逻辑,最后返回true
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
//将要发送的具体事件存到postingState.event
postingState.event = event;
//将接收者存到postingState.subscription中
postingState.subscription = subscription;
boolean aborted;
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;
}
postSingleEventForType()方法最主要的操作就是根据事件类型获取订阅者列表,然后遍历这个列表发送事件,具体的发送事件的逻辑在postToSubscription()方法中,我们继续跟:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
//按照接收消息的方法的线程类型进行不同的处理
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
//如果接收消息的方法的threadMode是POSTING,就直接通过反射调用接收消息的方法
invokeSubscriber(subscription, event);
break;
case MAIN:
//如果接收消息的方法的threadMode是MAIN,而且当前在主线程,就直接调用接收消息的方法
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
//如果当前不在主线程中,就通过mainThreadPoster将消息添加到消息列表中
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
//如果接收消息的方法的threadMode是MAIN_ORDERED,而且mainThreadPoster不为空,就将event添加到mainThreadPoster的消息队列中
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
//如果接收消息的方法的threadMode是BACKGROUND,而且当前在主线程中,就通过backgroundPoster发送消息
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
//如果当前不在主线程中,就直接调用接收消息的方法
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
//如果接收消息的方法的threadMode是ASYNC,就通过asyncPoster.enqueue()发送消息
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
/**
* 通过反射调用接收消息的方法
**/
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);
}
}
从上面的代码中我们可以知道,如果当前线程和接收消息的方法所要求的线程在同一个线程,就直接通过反射调用接收消息的方法。如果接收消息的方法所要求的线程和当前线程不在同一个线程中,就通过poster发送消息。在上面的代码中我们看到了三个poster,分别是mainThreadPoster,backgroundPoster,asyncPoster,下面我们分别看一下这三个poster是什么时候创建的,又是怎么发送消息的。
先看下mainThreadPoster。mainThreadPoster是在EventBus的构造方法中创建的,下面是mainThreadPoster的创建过程:
/**
* EventBus的构造方法
**/
EventBus(EventBusBuilder builder) {
logger = builder.getLogger();
subscriptionsByEventType = new HashMap<>();
typesBySubscriber = new HashMap<>();
stickyEvents = new ConcurrentHashMap<>();
//通过builder.getMainThreadSupport()获取mainThreadSupport
mainThreadSupport = builder.getMainThreadSupport();
//通过mainThreadSupport.createPoster()创建mainThreadPoster
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
//直接创建BackgroundPoster
backgroundPoster = new BackgroundPoster(this);
//直接创建AsyncPoster
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;
}
/**
* EventBusBuilder的getMainThreadSupport方法
**/
MainThreadSupport getMainThreadSupport() {
if (mainThreadSupport != null) {
return mainThreadSupport;
} else if (AndroidLogger.isAndroidLogAvailable()) {
//获取主线程的Looper
Object looperOrNull = getAndroidMainLooperOrNull();
//如果主线程的Looper不为空,就根据这个Looper创建MainThreadSupport对象
return looperOrNull == null ? null :
new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
} else {
return null;
}
}
/**
* 这也是EventBusBuilder中的方法,可以获取主线程的Looper或null
**/
static Object getAndroidMainLooperOrNull() {
//通过Looper.getMainLooper()可以获取到主线程的Looper
try {
return Looper.getMainLooper();
} catch (RuntimeException e) {
// Not really a functional Android (e.g. "Stub!" maven dependencies)
return null;
}
}
/**
* MainThreadSupport类
* Interface to the "main" thread, which can be whatever you like. Typically on Android, Android's main thread is used.
*/
public interface MainThreadSupport {
boolean isMainThread();
Poster createPoster(EventBus eventBus);
class AndroidHandlerMainThreadSupport implements MainThreadSupport {
private final Looper looper;
public AndroidHandlerMainThreadSupport(Looper looper) {
this.looper = looper;
}
@Override
public boolean isMainThread() {
return looper == Looper.myLooper();
}
/**
* 通过EventBus对象和主线程的looper创建一个HandlerPoster
**/
@Override
public Poster createPoster(EventBus eventBus) {
return new HandlerPoster(eventBus, looper, 10);
}
}
}
通过上面的代码可以知道mainThreadPoster是一个HandlerPoster对象,它是在EventBus中通过AndroidHandlerMainThreadSupport.createPoster()方法创建的。创建mainThreadPoster是要用到一个looper,这个looper就是Android主线程中的looper。到这我们可能会想到mainThreadPoster是一个Handler对象,没错事实就是这样,我们看下HandlerPoster类:
/**
* HandlerPoster继承了Handler对象,同时实现了Poster接口
**/
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 pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
//通过sendMessage()方法发送消息
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
......
}
通过HandlerPoster的源码可以看到enqueue()方法是通过调用Handler的sendMessage()方法发送消息的。到这里我们就明白了mainThreadPoster的创建过程,也明白了从非UI线程向主线程发送消息是通过Handler实现的。至于Handler的机制,我们在你真的懂Android Handler吗?(一)系列文章中介绍了。
了解了mainThreadPoster的创建过程以及从非UI线程向UI线程发送消息的机制,我们再来看下backgroundPoster发送消息的逻辑。
在分析mainThreadPoster创建过程的代码中我们知道backgroundPoster是在EventBus的构造方法中直接创建的,那么我们再看下BackgroundPoster类,看下它是怎么发送消息的。
/**
* BackgroundPoster实现了Runnable接口,同时实现了Poster接口
* Posts events in background.
*
* @author Markus
*/
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的线程池中
eventBus.getExecutorService().execute(this);
}
}
}
@Override
public void run() {
try {
try {
while (true) {
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()方法通过反射调用接收消息的方法
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
}
可以看到BackgroundPoster继承了Runnable接口,同时实现了Poster接口,当再EventBus中调用backgroundPoster.enqueue()发送消息时其实就是将消息和接收消息的方法封装到PendingPost中,再将PendingPost对象放到队列中。然后把backgroundPoster对象添加到线程池中,之后的操作是在线程池中进行的。
在BackgroundPoster的run()方法中从PendingPost队列中每隔一秒取一个PendingPost对象,然后调用event.invokeSubscriber()方法利用反射机制调用接收消息的方法。
现在我们也知道了从主线程向自线程发送消息是通过线程池进行的。
最后我们还需要看下asyncPoster的代码。asyncPoster是AsyncPoster类型的对象,它也是在EventBus的构造方法中被直接创建的,下面是AsyncPoster的源码:
/**
* Posts events in background.
*
* @author Markus
*/
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);
}
}
很明显,AsyncPoster和BackgroundPoster的逻辑是相似的。
OK,现在我们追踪了EventBus的大部分源码,我们也可以回答文章开头的几个问题了
1、EventBus是怎么管理观察者的,如果我们在onCreate()方法中调用两次register()方法,当EventBus发送消息是会不会收到两条消息;
EventBus将消息类型和接收消息的方法通过Map对应在一起,这样即使我们在一个类中调用两次register()方法,当EventBus发送一条消息时,该类也不会收到两条消息。
2、上面代码中我们使用了EventBus.getDefault()获取了一个EventBus对象,那么我们是不是可以配置适合自己的EventBus对象,EventBus可以进行哪些配置?
在EventBus中我们最主要的配置是提供自己的线程池,以及设置消息类型A继承自消息类型B时,如果发送A类型的消息订阅了B的订阅者是否能收到消息。但是这些配置是不建议的。
3、EventBus中的消息是怎么传递的?
如果发送消息时的线程正好在接收消息所要求的线程中,就直接通过反射调用订阅者的方法(ThreadMode.MAIN_ORDERED除外),否则通过Poster.enqueue()发送消息,从非UI线程向UI线程传递消息是通过Handler实现的,而从一个线程向另一个非UI线程发送消息是通过在线程池中以反射的方式调用订阅者的订阅方法。
4、EventBus是怎么进行线程切换的?
见问题3。
5、EventBus中有粘性事件,粘性事件是怎么实现的?
粘性事件其实就是在EventBus的stickyEvents属性中存储了这些消息,当一个新的订阅者订阅之后就从stickyEvents中查找相关类型的消息,然后发送给订阅者。
好了,EventBus源码追踪完毕。