EventBus源码学习,震撼来袭

// subscriptionsByEventType是一个Map集合,key是事件类型,验证了我上面的猜想

CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);

// 如果subscriptions是null,则new出一个CopyOnWriteArrayList,并且往Map集合中添加

if (subscriptions == null) {

subscriptions = new CopyOnWriteArrayList<>();

subscriptionsByEventType.put(eventType, subscriptions);

} else {

// 这里做了if语句判断,判断一下List集合中是否存在,存在就抛异常

// 如果不存在?怎么没有add操作? 保持疑问

if (subscriptions.contains(newSubscription)) {

throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "

  • eventType);

}

}

以上的操作验证了我之前的猜想,通过if (subscriptions.contains(newSubscription)) 这个if语句判断 是否发生了重复注册,注意这里重复注册的含义是 事件类型一致,以及方法名也一致。

接下来我们看看如果一个注册对象重复注册了事件Event(方法名不能一致),优先级priority是如何设置的

int size = subscriptions.size();

for (int i = 0; i <= size; i++) {

// 这里判断subscriberMethod的优先级是否是大于集合中的subscriberMethod的优先级,如果是,把newSubscription插进去

// 这也表明了subscription中priority大的在前,这样在事件分发时就会先获取。

if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {

subscriptions.add(i, newSubscription);

break;

}

}

if语句的条件subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) ,保证了subscription中priority大的在前。同时i == size 这个条件也保证了priority小的也会添加到subscriptions集合中去

紧接着我们看看EventBus是如何处理粘性事件的:

List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);

if (subscribedEvents == null) {

subscribedEvents = new ArrayList<>();

typesBySubscriber.put(subscriber, subscribedEvents);

}

subscribedEvents.add(eventType);

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).

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);

}

}

}

注意以上代码有四行比较重要的注释信息。大致的意思是必须考虑eventType所有子类的现有粘性事件,在迭代的过程中,所有的event可能会因为大量的sticky events变得低效,为了使得查询变得高效应该改变数据结构。

isAssignableFrom方法的意思是判断candidateEventType是不是eventType的子类或者子接口,如果postSticky()的参数是子Event,那么@Subscribe注解方法中的参数是父Event也可以接收到此消息。

拿到粘性Event后,调用了checkPostStickyEventToSubscription()方法,改方法内部方法内部调用了postToSubscription()

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, Looper.getMainLooper() == Looper.myLooper());

}

}

步骤2总结:至此,EventBus的注册操作已经全部分析完了,需要注意的是,粘性事件是在subscribe中进行post的

(二) 发送事件:EventBus.getDefault().post(xxx);

普通Event

public void post(Object event) {

PostingThreadState postingState = currentPostingThreadState.get();

List eventQueue = postingState.eventQueue;

// 将Event添加到List集合中去

eventQueue.add(event);

if (!postingState.isPosting) {

postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();

postingState.isPosting = true;

if (postingState.canceled) {

throw new EventBusException(“Internal error. Abort state was not reset”);

}

try {

// 遍历这个list集合,条件是集合是否是空的

while (!eventQueue.isEmpty()) {

postSingleEvent(eventQueue.remove(0), postingState);

}

} finally {

postingState.isPosting = false;

postingState.isMainThread = false;

}

}

}

首先将当前的 Event添加到eventQueue中去,并且while循环,处理post每一个Event事件,调用的是 postSingleEvent(eventQueue.remove(0), postingState):

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {

// 获取Event的Class对象

Class<?> eventClass = event.getClass();

boolean subscriptionFound = false;

// eventInheritance初始化的时候值为true,所以会走该分支

if (eventInheritance) {

// 获取当前的Event的Class对象的所有父类的Class对象集合,优先从缓存里读取。

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);

}

}

这里lookupAllEventTypes()方法也是为了获取当前的Event的Class对象的所有父类的Class对象集合,优先从缓存里读取。之后是 for循环获取到的Class对象集合,调用postSingleEventForEventType()方法:

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {

CopyOnWriteArrayList subscriptions;

synchronized (this) {

// subscriptionsByEventType该map是在subscribe()方法中进行了put操作

subscriptions = subscriptionsByEventType.get(eventClass);

}

if (subscriptions != null && !subscriptions.isEmpty()) {

for (Subscription subscription : subscriptions) {

postingState.event = event;

postingState.subscription = subscription;

boolean aborted = false;

try {

// 进行for循环并调用了postToSubscription()

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;

}

postSingleEventForEventType()方法,主要是获取Event的Class对象所对应的一个List集合,集合的对象是Subscription参数。subscriptionsByEventType对象是在subscribe()方法中进行了赋值。for循环CopyOnWriteArrayList集合,并调用postToSubscription()

线程模型

等执行到postToSubscription()方法时,线程模型才派上了用场。

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 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);

}

第一个分支:线程模型是POSTING,直接调用了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);

}

}

很明显的看到,这是基于反射去调用方法,invoke方法接收两个参数,第一个参数是注册的对象,第二个参数是事件的Event。

从这里就可以看出来,POST并没有去做线程的调度什么的,事件处理函数的线程跟发布事件的线程在同一个线程。

第二个分支:线程模型是MAIN 首先判断了下事件发布的线程是不是主线程,如果是,执行invokeSubscriber()方法,invokeSubscriber()上面已经分析过,如果不是主线程,执行mainThreadPoster.enqueue(subscription, event)mainThreadPoster是继承自Handler,从这里大概可以猜到,这一步是去做线程调度的。/font>

我们看一看mainThreadPosterenqueue做了什么事:

void enqueue(Subscription subscription, Object event) {

// 封装了一个PendIngPost

PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);

synchronized (this) {

// 将PendIngPost压入队列

queue.enqueue(pendingPost);

if (!handlerActive) {

handlerActive = true;

// 调用了sendMessage()

if (!sendMessage(obtainMessage())) {

throw new EventBusException(“Could not send handler message”);

}

}

}

}

enqueue() 主要封装了一个PendingPost类,并把subscriptionevent作为参数传进去,紧接着把PendingPost压入到队列中去,然后sendMessage发了一条消息。

熟悉Handler机制的同学知道,处理消息是在handleMessage()方法中完成的:

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;

}

}

代码有点多,我们主要看一下,它接收到消息后,是做了什么处理。从队列中取了消息,并且调用了eventBus.invokeSubscriber(pendingPost)方法,回到EventBus类中。

void invokeSubscriber(PendingPost pendingPost) {

Object event = pendingPost.event;

Subscription subscription = pendingPost.subscription;

PendingPost.releasePendingPost(pendingPost);

if (subscription.active) {

invokeSubscriber(subscription, event);

}

}

该方法内部还是去调用了invokeSubscriber()方法。

分析完线程模型为MAIN 的工作流程,不难做出结论,当发布事件所在的线程是在主线程时,我们不需要做线程调度,直接调用反射方法去执行。如果发布事件所在的线程不是在主线程,需要使用Handler做线程的调度,并最终调用反射方法去执行

第三个分支:线程模型是BACKGROUND。如果事件发布的线程是在主线程,执行backgroundPoster.enqueue(subscription, event),否则执行invokeSubscriber()

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);

}

}

}

PendingPost对象压入队列,然后调用eventBus.getExecutorService().execute(this),交给线程池去进行处理,它的处理是在Runnable的run()中。backgroundPoster实现了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) {

Log.w(“Event”, Thread.currentThread().getName() + " was interruppted", e);

}

} finally {

executorRunning = false;

}

}

最重要的还是eventBus.invokeSubscriber(pendingPost)这行代码,上面已经分析过。

第四个分支:线程模型是ASYNC。直接调用 asyncPoster.enqueue(subscription, event)asyncPoster也是实现了Runnable接口,里面也是使用的线程池,具体的操作就不分析了,感兴趣的可以去看一下源码,跟上一步操作类似。

(三) 高级用法

EventBus3.0较之前的版本有了一次改造,在3.0之后增加了注解处理器,在程序的编译时候,就可以根据注解生成相对应的代码,相对于之前的直接通过运行时反射,大大提高了程序的运行效率,但是在3.0默认的还是通过反射去查找用@Subscribe标注的方法,一般在使用的时候基本都是这个模式。 那我们怎么配置让EventBus使用注解器生成的代码呢? EventBus官网apt介绍

在这里我们重点提一下 EventBusBuilder类的:

boolean ignoreGeneratedIndex;

List subscriberInfoIndexes;

subscriberInfoIndexes变量可以去使用注解处理器生成的代码。SubscriberInfoIndex 就是一个接口,而注解生成器生成的类也是继承的它,我们也可以自己去继承它,定制自己的需求,不需要反射的EventBus。

我们再回过头来看一下注册过程的findUsingInfo()方法:

private List findUsingInfo(Class<?> subscriberClass) {

FindState findState = prepareFindState();

findState.initForSubscriber(subscriberClass);

while (findState.clazz != null) {

findState.subscriberInfo = getSubscriberInfo(findState);

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 {

findUsingReflectionInSingleClass(findState);

}

findState.moveToSuperclass();

}

return getMethodsAndRelease(findState);

}

我们在前面分析的时候,直接分析的 findUsingReflectionInSingleClass(findState)方法,因为getSubscriberInfo()返回null,那什么时候getSubscriberInfo()返回不为null呢 ? 我们具体看看getSubscriberInfo()

private SubscriberInfo getSubscriberInfo(FindState findState) {

if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {

SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();

if (findState.clazz == superclassInfo.getSubscriberClass()) {

return superclassInfo;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

berInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {

SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();

if (findState.clazz == superclassInfo.getSubscriberClass()) {

return superclassInfo;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-xcvT02pb-1710923832789)]
[外链图片转存中…(img-6SKIdJWu-1710923832790)]
[外链图片转存中…(img-rgoyvytG-1710923832790)]
[外链图片转存中…(img-XsxTuDKT-1710923832791)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-yuxVT8lJ-1710923832791)]

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值