EventBus 普通事件的post
当订阅事件完成后,就需要发送时间通知了,调用比较简单
EventBus.getDefault().post(eventType);
看一下post事件:
/** Posts the given event to the event bus. */
public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
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()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
首先出现了一个currentPostingThreadState,他是干啥的?
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
他是一个ThreadLocal,这个是干啥的?当有多线程进行操作的时候,有的资源可以保存在线程本地使用,免争抢排队;叫他线程本地变量;
引用一句话:Java并发编程:深入剖析ThreadLocal
ThreadLocal,很多地方叫做线程本地变量,也有些地方叫做线程本地存储,其实意思差不多。可能很多朋友都知道ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
初始化的时候创建了一个PostingThreadState对象,点进去看一下,发现他是EventBus的一个静态内部类,还是final类型的;
/** 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;
}
看看注释:供线程本地变量使用,使之更快set/get;由此知道,就一中间产物,用于事件发送时记录操作过程中的某些状态的;
因为post可以在跨线程操作,所以存在这么一个东西;
回到代码中,先取得线程本地变量的对象;将参数添加到发送状态的List集合中;
postingState.isPosting
默认是false,所以直接进入if中;他相当于一个开关,进去之后立马将状态改为true,发送完成或者失败后才置false;
postingState.isMainThread = isMainThread();
判断当前是否是主线程;
往里追一下代码:
private boolean isMainThread() {
return mainThreadSupport != null ? mainThreadSupport.isMainThread() : true;
}
// @Nullable
private final MainThreadSupport mainThreadSupport;
private boolean isMainThread() {
return mainThreadSupport != null ? mainThreadSupport.isMainThread() : true;
}
EventBus初始化的时候默认调用了EventBusBuilder中的getMainThreadSupport:
MainThreadSupport getMainThreadSupport() {
if (mainThreadSupport != null) {
return mainThreadSupport;
} else if (Logger.AndroidLogger.isAndroidLogAvailable()) {
Object looperOrNull = getAndroidMainLooperOrNull();
return looperOrNull == null ? null :
new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
} else {
return null;
}
}
判断是否是null,刚来肯定是的;看一下else if
(Logger.AndroidLogger.isAndroidLogAvailable()
这是什么玩意儿?追进去看看
public interface Logger {
......
public static class AndroidLogger implements Logger {
static final boolean ANDROID_LOG_AVAILABLE;
static {
boolean android = false;
try {
android = Class.forName("android.util.Log") != null;
} catch (ClassNotFoundException e) {
// OK
}
ANDROID_LOG_AVAILABLE = android;
}
public static boolean isAndroidLogAvailable() {
return ANDROID_LOG_AVAILABLE;
}
......
}
......
}
看方法名:isAndroidLogAvailable,Android的Log是否可用,判断条件就是看是否能找的到android系统的log类:
android = Class.forName("android.util.Log") != null;
找不到说明这事没得谈,你一个Android APP程序,你找不到android.util.Log,你还是在Android代码中?还谈什么主(UI)线程啊!(浅见啊,比较肤浅)
现在假设这事是定的,就直接走的else if代码;
Object looperOrNull = getAndroidMainLooperOrNull();
Object getAndroidMainLooperOrNull() {
try {
return Looper.getMainLooper();
} catch (RuntimeException e) {
// Not really a functional Android (e.g. "Stub!" maven dependencies)
return null;
}
}
拿到主线程的Looper,如果拿不到返回null(注释:// Not really a functional Android (e.g. “Stub!” maven dependencies))
我们按照正常流程走,拿到主线程的Looper之后,
new MainThreadSupport.AndroidHandlerMainThreadSupport((Looper) looperOrNull);
哎,牵扯的又有点远了…
/**
* 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();
}
@Override
public Poster createPoster(EventBus eventBus) {
return new HandlerPoster(eventBus, looper, 10);
}
}
}
把主线程的Looper传进来,下次被调用isMainThread()时,直接拿当前线程的Looper和主线程对比判断;看这个接口名字起的,就是为主线程做支撑的;
现在回到正轨上;
判断当前线程是否是主线程;
然后判断当前发送事件是否取消了,取消就抛异常;没呢…
判断发送类型参数集合是否为空,凡事都要讲第一次,第一次肯定是不为空的
postSingleEvent(eventQueue.remove(0), postingState);
看方法名字:发送单个事件
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
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) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}
看传进来的参数,第一个:取出并移除参数队列中的第一个参数、第二个参数:线程发送状态对象;
获取传进来参数的class,(还记得之前的约定名词吗将订阅者和包装过的订阅方法SubscriberMethod组装的Subscription,我叫他订阅者方法),设置一个是否找到订阅者方法的标签subscriptionFound,默认false;
eventInheritance:神奇的东西,设置参数类型的继承性,假设参数类型A继承于B并实现了C接口,当设置为true的时候,发送A类型的事件时,A、B、C参数类型的方法都能接收得到;默认是true;如果想动手脚的话,也就是在EventBusBuilder中设置不具有继承性;
进入if中:
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
/** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */
private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) {
synchronized (eventTypesCache) {
List<Class<?>> eventTypes = eventTypesCache.get(eventClass);
if (eventTypes == null) {
eventTypes = new ArrayList<>();
Class<?> clazz = eventClass;
while (clazz != null) {
eventTypes.add(clazz);
addInterfaces(eventTypes, clazz.getInterfaces());
clazz = clazz.getSuperclass();
}
eventTypesCache.put(eventClass, eventTypes);
}
return eventTypes;
}
}
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
又是一个Map,为什么要说又?
看一下代码可以知道:Key是传进来的参数类型的class,Value是eventTypes,eventTypes是一个List,里面装载的是参数类型;看到这里是不是有点蒙蔽,把自己做Key,又把自己塞到List中做Value,有病吧!但是别忘了,我们是从if进来的,if代表什么,参数类型有继承性,也就是具有"传染病仔细看,里面有个while方法
while (clazz != null) {
eventTypes.add(clazz);
addInterfaces(eventTypes, clazz.getInterfaces());
clazz = clazz.getSuperclass();
}
这时干啥?这就是找到所有的"感染者";
先把自己塞到List中;
/** Recurses through super interfaces. */
static void addInterfaces(List<Class<?>> eventTypes, Class<?>[] interfaces) {
for (Class<?> interfaceClass : interfaces) {
if (!eventTypes.contains(interfaceClass)) {
eventTypes.add(interfaceClass);
addInterfaces(eventTypes, interfaceClass.getInterfaces());
}
}
}
把容器扔进去,把所有接口扔进去;只要有某个接口类型没有加到容器中就扔进去,然后是接口的接口,递归的把所有接口类型都扔进去,然后跳到父类中,把父类扔进去,接着找接口扔;
最终把所有的父类、接口类型都扔到集合里面,然后将该参数类型对应的这一List集合扔到Map中,并返回所有的事件类型;
拿到所有的事件类型后开始遍历;
postSingleEventForEventType(event, postingState, clazz);
传入的参数是post进来的事件类型对象,状态对象,遍历的事件类型
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;
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;
}
有一个subscriptionsByEventType,妈的,Map;
用参数类型的class作为Key,所有的该参数类型的订阅者方法的List作为Value;
找到所有的订阅者方法;
只要注册过了就不会为null;还是第一次,不为空;
取得参数类型对象和订阅者方法,并设置一个aborted标签,它是用于判断post事件是否被取消;
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
......
case MAIN:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
......
}
}
这里只关注Main,
判断是否是主线程而执行不同的方法,我们是默认走的主线程;
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);
}
}
根据参数订阅者对象,订阅者参数值,直接反射调用订阅方法;
主线程的是走完了,那再来看看非主线程中执行的方法;
mainThreadPoster.enqueue(subscription, event);
传进来的参数是订阅者方法对象和参数对象;
mainThreadPoster这个是什么?还记得mainThreadSupport吧,默认使用mainThreadSupport的createPoster
@Override
public Poster createPoster(EventBus eventBus) {
return new HandlerPoster(eventBus, looper, 10);
}
创建了一个HandlerPoster对象;
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;
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;
}
}
}
继承于Handler,所以他也是一个handler;
执行了enqueue方法;
又牵扯出一个PendingPost,
final class PendingPost {
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;
}
static PendingPost obtainPendingPost(Subscription subscription, Object event) {
synchronized (pendingPostPool) {
int size = pendingPostPool.size();
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);
}
}
}
}
看名字:PendingPost,等待发送;
内部维持了一个池子,大小小于10000,用完之后把对象值清空扔进池子,用的时候从池子尾部取出并移除一个空值对象,然后赋值,并将该对象返回;如果池子是空的,则新建一个等待post对象并赋值返回;
回到HandlerPoster中,获取到一个等待post对象后;
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;
}
synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
if (head == null) {
wait(maxMillisToWait);
}
return poll();
}
}
看代码就是一个链表的节点类;执行enqueue方法,如果是第一个则将头尾指针指向该等待post对象,否则就是往尾上加,最后唤醒该线程,抢夺时间片执行;
设置一个handlerActive标签,是否正在处理中,在里面发送事件,同时handleMessage相应执行;
还记得HandlerPoster是在哪创建的吧,没错,是在主线程中创建的,所以handleMessage是在主线程中执行的,不要切换线程了(假设更新UI的话);
记录开始的时间,然后死循环进去如果链表空了,那就中断了,否则就执行
eventBus.invokeSubscriber(pendingPost);
先不管,往下看,最后handlerActive标签改变,退出死循环,方法结束;
取得当前时间与开始时间的时间差,只要大于10毫秒(为什么是10毫秒,传进来的就是10毫秒),就重发消息,这是为了避免队列过长是,while循环阻塞主线程造成卡顿。
再回过头来看看eventBus.invokeSubscriber(pendingPost);
void invokeSubscriber(PendingPost pendingPost) {
Object event = pendingPost.event;
Subscription subscription = pendingPost.subscription;
PendingPost.releasePendingPost(pendingPost);
if (subscription.active) {
invokeSubscriber(subscription, event);
}
}
拿到参数对象,拿到订阅者方法,释放等待post占用的资源内存;
只要没有解注册,就调用invokeSubscriber(subscription, event);看来殊途同归啊,也是反射调用订阅方法;
这里就结束了,post事件就发送出去了;
接着往回填坑;
不管主线程还是非主线程方法执行完之后,也就是postToSubscription方法结束了;
最终发送状态postingState释放资源内存;且返回true;没有没有找到订阅者方法,就返回false;
只要找到了subscriptionFound标签就会为true;
如果没有参数类型的继承性,就只会执行当前参数的
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
效果和之前一样;
同样如果没有找到订阅者方法,sendNoSubscriberEvent默认是true;直接发送一个NoSubscriberEvent类型的事件通知;到了post方法中,NoSubscriberEvent对象被添加到了eventQueue中,但是此时isPosting还是true,被拦截了进不去if,postSingleEvent事件结束,但是由于eventQueue中添加了NoSubscriberEvent事件,所以while并没有结束,再次调用postSingleEvent,这时的参数是NoSubscriberEvent对象,这次是肯定找不到NoSubscriberEvent类型的订阅者方法的,所以subscriptionFound=false,又进入了if判断中,但是这次
eventClass != NoSubscriberEvent.class
该条件不成立,所以该方法结束,然后post中的while因为没数据了也结束了循环,postingState释放剩下的占用资源内存;
到这里彻底结束了普通事件的post。
参考: