[EventBus源码分析(一):入口函数提纲挈领(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51802172)
[EventBus源码分析(二):register方法保存事件的订阅者列表(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51819508)
[EventBus源码分析(三):post方法发布事件【获取事件的所有订阅者,反射调用订阅者事件处理方法】(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51821143)
[EventBus源码分析(四):线程模型分析(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51832001)
[EventBus源码解读详细注释(1)register的幕后黑手](http://blog.csdn.net/wangshihui512/article/details/50914817)
[EventBus源码解读详细注释(2)MainThread线程模型分析](http://blog.csdn.net/wangshihui512/article/details/50934012)
[EventBus源码解读详细注释(3)PostThread、MainThread、BackgroundThread、Async四种线程模式的区别](http://blog.csdn.net/wangshihui512/article/details/50935729)
[EventBus源码解读详细注释(4)register时刷新的两个map](http://blog.csdn.net/wangshihui512/article/details/50938663)
[EventBus源码解读详细注释(5)事件消息继承性分析 eventInheritance含义](http://blog.csdn.net/wangshihui512/article/details/50947102)
[EventBus源码解读详细注释(6)从事件发布到事件处理,究竟发生了什么!](http://blog.csdn.net/wangshihui512/article/details/50949960)
EventBus的线程模型
为何要定义线程模型?因为在Android的中线程的使用有以下的限制:
1 主线程不能被阻塞,UI的更新位于主线程,耗时操作如网络处理在后台线程
2 事件的发送和处理可能会位于不同线程
通过使用EvenBus的线程模型,我们可以定义处理事件的线程模型。EventBus中有四种线程模型:PostThread,MainThread,BackgroundThread,Async,下面分别介绍之。
PostThread
默认的线程模型,事件发布和接收在相同的线程,适合用于完成时间非常短的任务,以免阻塞UI。例:
// Called in the same thread (default)
public void onEvent(MessageEvent event) {
log(event.message);
}
MainThread
订阅者的事件处理方法在主线程被调用,适合处理开销小的事件,以免阻塞主线程。例:
// Called in Android UI's main thread
public void onEventMainThread(MessageEvent event) {
textField.setText(event.message);
}
BackgroundThread
订阅者的事件处理在后台被调用。若事件发送线程位于主线程,EventBus将使用一个后台线程来逐个发送事件
// Called in the background thread
public void onEventBackgroundThread(MessageEvent event){
saveToDisk(event.message);
}
Async
事件处理位于一个单独的线程,该线程往往既不是发送事件的线程,也不是主线程。使用这个模型适用于事件发送无需等待事件处理后才返回,适合处理耗时操作,如请求网络。EventBus内部使用线程池来管理多个线程。例:
// Called in a separate thread
public void onEventAsync(MessageEvent event){
backend.send(event.message);
}
接下来从源码的角度分析MainThread
EventBus有个私有方法
postToSubscription,这个私有方法是如何调用的且听下回分解,先不管
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { case PostThread: invokeSubscriber(subscription, event); break; case MainThread: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break;通过解析线程模型,如果是MainThread线程模型,并且当前线程就是主线程,那么可以直接在当前主线程通过反射调用订阅者的事件处理方法;
如果当前线程不是主线程呢?当然只能借助Handler了,将此事件发送到主线程处理。
mainThreadPoster是EventBus的一个属性,类型为HandlerPoster
是这样构造的
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);传入的第二个参数是主线程的Looper,第三个参数表示主线程事件处理最大时间为10ms,超时将重新调度事件
下边看下HandlerPoster的内部是干什么的
final class HandlerPoster extends Handler {
private final PendingPostQueue queue;
/*事件处理最大时间,超时重新调度*/
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
/*入队列操作,传入订阅者和事件*/
void enqueue(Subscription subscription, Object event) {
/*将订阅者和事件封装成PendingPost*/
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
/** public final boolean sendMessage(Message msg)
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in handleMessage,
* in the thread attached to this handler.
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
/** public final Message obtainMessage()
* Returns a new android.os.Message Messagefrom the global message pool. More efficient than
* creating and allocating new instances. The retrieved message has its handler set to this instance
* (Message.target == this).
*/
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
/** native public static long uptimeMillis();
* Returns milliseconds since boot, not counting time spent in deep sleep.
* @return milliseconds of non-sleep uptime since boot.
*/
/*记录循环开始的时间*/
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;
}
}
}
这个类主要实现了一个在UI线程也就是主线程循环处理事件的功能,同时如果事件处理超时,将被重新调度。
顺便看下EventBus的数据结构是如何设计的
先看消息队列:
再看消息类:final class PendingPostQueue { private PendingPost head; private PendingPost tail; /*入队列操作*/ synchronized void enqueue(PendingPost pendingPost) { /*良好编程习惯,入口参数检查*/ if (pendingPost == null) { throw new NullPointerException("null cannot be enqueued"); } /*尾部不是空指针,队列有尾部,后边加一个PendingPost数据,该数据指针域已初始化为空指针*/ if (tail != null) { tail.next = pendingPost; tail = pendingPost; /*队列头部为空指针,那么肯定没有头部,也没有尾部,队列为空,把入队的新元素作为头部和尾部*/ } else if (head == null) { head = tail = pendingPost; /*队列有头无尾抛出异常*/ } else { throw new IllegalStateException("Head present, but no tail"); } /** * Causes all threads which are waiting on this object's monitor (by means * of calling one of the code wait() methods) to be woken up. The threads * will not run immediately. The thread that called code notify() has to * release the object's monitor first. Also, the threads still have to * compete against other threads that try to synchronize on the same object. *This method can only be invoked by a thread which owns this object's * monitor. A thread becomes owner of an object's monitor * by executing a synchronized method of that object; * by executing the body of a code synchronized statement that synchronizes on the object; * by executing a synchronized static method if the object is of type code Class * 1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。 2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁) 3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程, 如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程; 4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程; 调用某个对象的wait()方法,当前线程必须拥有这个对象的monitor(即锁), 因此调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法) 调用某个对象的wait()方法,相当于让当前线程交出此对象的monitor,然后进入等待状态, 等待后续再次获得此对象的锁(Thread类中的sleep方法使当前线程暂停执行一段时间,从而让其他线程有机会继续执行,但它并不释放对象锁); notify()方法能够唤醒一个正在等待该对象的monitor的线程,当有多个线程都在等待该对象的monitor的话, 则只能唤醒其中一个线程,具体唤醒哪个线程则不得而知。 同样地,调用某个对象的notify()方法,当前线程也必须拥有这个对象的monitor, 因此调用notify()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。 nofityAll()方法能够唤醒所有正在等待该对象的monitor的线程,这一点与notify()方法是不同的。 这里要注意一点:notify()和notifyAll()方法只是唤醒等待该对象的monitor的线程,并不决定哪个线程能够获取到monitor。 一个线程被唤醒不代表立即获取了对象的monitor,只有等调用完notify()或者notifyAll()并退出synchronized块, 释放对象锁后,其余线程才可获得锁执行。 */ notifyAll(); } /*队首出队列*/ synchronized PendingPost poll() { PendingPost pendingPost = head; if (head != null) { /*队首出队列,将原队列第二个数据作为新的队首*/ /*注意原队列只有一个数据的情况,队首==队尾都不是null,现在若队首出队列,队尾应该设置null*/ head = head.next; if (head == null) { tail = null; } } /*队列为空,返回空指针*/ return pendingPost; } /*如果队列为空,挂起当前线程,知道有新的数据加入队列(入队列操作后调用了notifyall() )*/ synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException { if (head == null) { /** * Causes the calling thread to wait until another thread calls the * notify() or notifyAll()method of this object or until the * specified timeout expires. This method can only be invoked by a thread * which owns this object's monitor; * While the thread waits, it gives up ownership of this object's * monitor. When it is notified (or interrupted), it re-acquires the monitor * before it starts running. * A timeout of zero means the calling thread should wait forever unless interrupted or * notified. * wait(): 等待对象的同步锁,需要获得该对象的同步锁才可以调用这个方法, 否则编译可以通过,但运行时会收到一个异常:IllegalMonitorStateException。 调用任意对象的 wait() 方法导致该线程阻塞,该线程不可继续执行,并且该对象上的锁被释放。 notify(): 唤醒在等待该对象同步锁的线程(只唤醒一个,如果有多个在等待),注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程, 而是由JVM确定唤醒哪个线程,而且不是按优先级。 调用任意对象的notify()方法则导致因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。 notifyAll(): 唤醒所有等待的线程,注意唤醒的是notify之前wait的线程,对于notify之后的wait线程是没有效果的。 */ wait(maxMillisToWait); } /*获得对象锁后返回队首数据*/ return poll(); } }
final class PendingPost { /*开一个对象池,静态ArrayList实现*/ private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>(); /*数据部分是事件和订阅者*/ Object event; Subscription subscription; /*保持链表结构,指向下一个节点*/ PendingPost next; /*私有构造函数,封装事件和订阅者*/ private PendingPost(Object event, Subscription subscription) { this.event = event; this.subscription = subscription; } /*传入事件和订阅者,返回一个封装好的PendingPost*/ static PendingPost obtainPendingPost(Subscription subscription, Object event) { /*对对象池加锁*/ synchronized (pendingPostPool) { int size = pendingPostPool.size(); /*如果对象池保存的有备胎对象,就用备胎对象,节省一次new对象*/ if (size > 0) { /*从池子里边拿出来一个PendingPost*/ /* * Removes the object at the specified location from this code List. * @param location the index of the object to remove. * @return the removed object. * 从池子也就是list拿出来一个PendingPost*/ 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); } } } }