事件分发的核心代码:
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所在线程。
订阅方法不同的线程模式,分发方式略有不同:
private final MainThreadSupport mainThreadSupport;
private final Poster mainThreadPoster;
private final BackgroundPoster backgroundPoster;
private final AsyncPoster asyncPoster;
mainThreadSupport = builder.getMainThreadSupport();
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
其中mainThreadSupport.createPoster(this) 实际是通过实例化对象调用createPoster方法返回new HandlerPoster(eventBus, looper, 10)得到主线程的handler
class AndroidHandlerMainThreadSupport implements MainThreadSupport {
private final Looper looper;
public AndroidHandlerMainThreadSupport(Looper looper) {
this.looper = looper;
}
@Override
public boolean isMainThread() {
return looper == Looper.myLooper();//获取主线程的looper,用哪个线程的looper创建handler,handler就运行在哪个线程。
}
@Override
public Poster createPoster(EventBus eventBus) {
return new HandlerPoster(eventBus, looper, 10);
}
}
public class HandlerPoster extends Handler implements Poster {
//PendingPostQueue队列,待发送的post队列
private final PendingPostQueue queue;
//规定最大的运行时间,因为运行在主线程,不能阻塞主线程
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
//传入的第二个参数是主线程的Looper,第三个参数表示主线程事件处理最大时间为10ms
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;
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 = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
}
HandlerPoster#handleMessage方法:
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
//死循环,从消息队列取出消息逐一处理
while (true) {
//获取队首
PendingPost pendingPost = queue.poll();
/*如果队列为空*/
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
//如果队里中没有消息需要处理,设置标志位,然后直接返回,退出循环
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
/*运用反射调用事件处理方法*/
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
两次判断pendingPost是否为空是处理多线程的同步问题,这里与单例模式是同样的道理。调用eventBus.invokeSubscriber处理事件,while循环超过10ms之后会退出handleMessage方法,并将handleActive置位true,并再次发送消息,使得该handler再次调用handleMessage()方法,继续处理队列中的注册信息,这是为了避免队列过长时,while循环阻塞主线程造成卡顿。
EventBus#invokeSubscriber 方法:
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
invokeSubscriber(subscription, event);
}
}
释放pendingPost,判断subscription.active是否有true,默认为true,只有在unregister中设置为false,接着调用 invokeSubscriber(subscription, event)反射执行订阅者的订阅方法。到此分发完毕。
判断subscription.active的原因注释有说,大概意思说,事件可能会在订阅方法未注册之后传递。
PendingPostQueue消息队列
final class PendingPostQueue {
private PendingPost head;
private PendingPost tail;
//入队列
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");
}
notifyAll();
}
synchronized PendingPost poll() {
PendingPost pendingPost = head;
if (head != null) {
head = head.next;
if (head == null) {
tail = null;
}
}
return pendingPost;
}
//如果队列为空,挂起当前线程,直到有新的数据加入队列(入队列操作后调用了notifyall() )
synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
if (head == null) {
wait(maxMillisToWait);
}
return poll();
}
}
队列是以链表的形式连接,从尾部加入,头部弹出。
调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程。
调用某个对象的wait()方法,当前线程必须拥有这个对象的monitor(即锁), 因此调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法) ,调用某个对象的wait()方法,相当于让当前线程交出此对象的monitor,然后进入等待状态, 等待后续再次获得此对象的锁(Thread类中的sleep方法使当前线程暂停执行一段时间,从而让其他线程有机会继续执行,但它并不释放对象锁)。
PendingPost类:封装了event事件和Subscription(订阅者和订阅方法)
final class PendingPost {
private final static List pendingPostPool = new ArrayList();
Object event;
Subscription subscription;
PendingPost next;
private PendingPost(Object event, Subscription subscription) {
this.event = event;
this.subscription = subscription;
}
static PendingPost obtainPendingPost(Subscription subscription, Object event) {
synchronized (pendingPostPool) {
int size = pendingPostPool.size();
//如果对象池保存的有备胎对象,就用备胎对象,节省一次new对象
if (size > 0) {
PendingPost pendingPost = pendingPostPool.remove(size - 1);
pendingPost.event = event;
pendingPost.subscription = subscription;
pendingPost.next = null;
return pendingPost;
}
}
return new PendingPost(event, subscription);
}
static void releasePendingPost(PendingPost pendingPost) {
pendingPost.event = null;
pendingPost.subscription = null;
pendingPost.next = null;
synchronized (pendingPostPool) {
// Don't let the pool grow indefinitely
if (pendingPostPool.size() < 10000) {
pendingPostPool.add(pendingPost);
}
}
}
}
订阅事件在子线程执行,两种情况:
private final BackgroundPoster backgroundPoster;
backgroundPoster = new BackgroundPoster(this);
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;
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(pendingPost);
}
} catch (InterruptedException e) {
eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
}
首先BackgroundPoster是实现Runnable接口,是一个可执行的任务,而mainThreadPoster是继承Handler进行事件分发。不过代码实现相识。
eventBus.getExecutorService().execute(this),进队列后判断此线程是否在执行,如果没有在执行就执行此线程(调用run方法),是通过线程池来执行Runable接口。
@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(pendingPost);
}
} catch (InterruptedException e) {
eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
执行流程与HandlerPoster相似,不过在取事件时,有一个等待时间,即queue.poll(1000),这里有一个等待过程,即从队列中取PendingPost对象时,如果没有PendingPost会等待1000毫秒。BackgroundPoster会将1000毫秒以内入队的事件消息在同一个线程中调用,这一点也是与AsyncPoster最重要的区别。
不管发布者处在主线程与否,为每一个事件单独开辟一个线程处理。
EventBus有专门的线程池对子线程进行管理,但仍然要避免同一时间开启太多的ASYNC模式线程。
private final AsyncPoster asyncPoster;
asyncPoster = new AsyncPoster(this);
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同样是实现Runnable接口,这里注意enqueue是同步的方法,不用担心同步问题,然后调用线程池的线程执行该Runnable,run方法的逻辑就是取出队列的pendingPost, 并执行invokeSubscriber方法,由于是入队一次调用一次execute方法,所以正常情况下队列中不会取不出pendingPost, 也不会剩余pendingPost。
前面也提到过BackgroundPoster设定一个时间上限,并且在该段时间内post过来的事件入队的订阅方法会在同一个线程中调用,而AsyncPoster则是完全异步的调用。也就是说BackgroundPoster会尽可能在同一线程中调用订阅方法,并且有一定的先后顺序,而AsyncPoster对订阅方法的调用则是完全异步,不确定在哪个线程,也不确定顺序。