面试官问我:Android EventBus的源码,看我如何用漫画装逼!(1)

接下来看EventBus的构造函数,源码如下:

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;

throwSubscriberException = builder.throwSubscriberException;

eventInheritance = builder.eventInheritance;

executorService = builder.executorService;

}

可以看到,在EventBus的构造函数中,初始化了一大堆变量,这边主要关注前面两个。

subscriptionsByEventType = new HashMap<>();:key:事件类型(如:MyEvent ),value:新的订阅对象的集合,包括订阅者和订阅者包含的方法。具体赋值逻辑在后面会讲,这边先了解即可。

typesBySubscriber = new HashMap<>();:key:事件的订阅者(MainActivity ),value:事件类型的集合。订阅者跟事件类型是一对多的关系,所以一个界面可以支持多个事件类型。

2)注册

/**

  • 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) {

//1.拿到订阅对象的类型;

Class<?> subscriberClass = subscriber.getClass();

//2.通过findSubscriberMethods方法获取该订阅者中的所有订阅方法,因为可能包含多个订阅方法,所以返回集合。

List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);

synchronized (this) {

for (SubscriberMethod subscriberMethod : subscriberMethods) {

//3.通过subscribe方法为每个订阅方法进行订阅。

subscribe(subscriber, subscriberMethod);

}

}

}

如何获取该订阅者中的所有订阅方法,这边主要看第二件事情的处理过程,及findSubscriberMethods方法的源码

List findSubscriberMethods(Class<?> subscriberClass) {

//先拿订阅对象在本地缓存中查找,提高性能。

List subscriberMethods = METHOD_CACHE.get(subscriberClass);

if (subscriberMethods != null) {

return subscriberMethods;

}

//默认情况下ignoreGeneratedIndex值是false的

if (ignoreGeneratedIndex) {

//使用反射方法拿到订阅者中的订阅方法

subscriberMethods = findUsingReflection(subscriberClass);

} else {

//使用编译期间生成的SubscriberInfo

subscriberMethods = findUsingInfo(subscriberClass);

}

//如果没有订阅方法,则抛出异常

if (subscriberMethods.isEmpty()) {

throw new EventBusException("Subscriber " + subscriberClass

  • " and its super classes have no public methods with the @Subscribe annotation");

} else {

//本地存储订阅方法,方便下次获取,提高了性能

METHOD_CACHE.put(subscriberClass, subscriberMethods);

return subscriberMethods;

}

}

可以看到上面方法做了三件事:

1.先拿订阅对象在本地缓存中查找订阅方法

2.如果本地获取不到,则根据ignoreGeneratedIndex的值决定获取订阅方法的方式

3.本地保存订阅方法。

可以看到获取订阅的关键方法为:findUsingInfo(),那么赶紧看下他的源码,如下:

private List findUsingInfo(Class<?> subscriberClass) {

FindState findState = prepareFindState();

findState.initForSubscriber(subscriberClass);

while (findState.clazz != null) {

// 获取订阅者信息,没有配置MyEventBusIndex返回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 {

// 通过反射来查找订阅方法,所以为了提高性能,我们还是要用索引的形式使用EventBus

findUsingReflectionInSingleClass(findState);

}

findState.moveToSuperclass();

}

return getMethodsAndRelease(findState);

}

获取到订阅方法后,我们看真正的注册方法subscribe(subscriber, subscriberMethod);

// Must be called in synchronized block

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {

//获取到事件类型(如:MyEvent )

Class<?> eventType = subscriberMethod.eventType;

//把订阅者和订阅者方法重新封装成新的对象

Subscription newSubscription = new Subscription(subscriber, subscriberMethod);

//事件类型为key,新的订阅者对象列表为value,存储进subscriptionsByEventType

//该集合很重要,当post消息的时候,就是从该集合中查找订阅者对象列表

CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);

if (subscriptions == null) {

//如果订阅者对象列表为空,则初始化出来,并加到subscriptionsByEventType中

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

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

// 根据订阅方法的优先级,添加到订阅列表

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

subscriptions.add(i, newSubscription);

break;

}

}

//订阅者为key,事件类型列表为value,存储进typesBySubscriber

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

}

}

}

可以看到上面方法做了两件事:

1.根据订阅方法的优先级,添加到订阅列表,事件类型为key,订阅列表为value,存储进subscriptionsByEventType

2.订阅者为key,事件类型列表为value,存储进typesBySubscriber

3)发送消息

/** Posts the given event to the event bus. */

public void post(Object event) {

PostingThreadState postingState = currentPostingThreadState.get();

List 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 {

//循环从列表中拿event

while (!eventQueue.isEmpty()) {

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

}

} finally {

postingState.isPosting = false;

postingState.isMainThread = false;

}

}

}

循环从eventQueue取event,调用postSingleEvent方法:

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

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

boolean subscriptionFound = false;

if (eventInheritance) {

//查找event事件和event子类事件

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

}

}

}

遍历每个event事件或者子类,会再调用postSingleEventForEventType:

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

CopyOnWriteArrayList subscriptions;

synchronized (this) {

//subscriptionsByEventType有没有很眼熟,在subscribe方法中,事件类型为key,新的订阅者对象列表为value,存储进subscriptionsByEventType

//获取到新的订阅对象列表

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集合中,查找该event对应的订阅者对象列表,然后遍历订阅者对象,调用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 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);

}

}

最后通过反射调用订阅者的方法。

通过上面的分析可以看到发送消息其实是三重循环:

1.循环从eventQueue取event,调用postSingleEvent方法

2.遍历每个event事件或者子类,调用postSingleEventForEventType方法

3.遍历订阅者对象,调用postToSubscription方法。

这种方式的算法复杂度还是很高的,event事件不做继承可以提高发送流程的性能。

4)解绑

/** Unregisters the given subscriber from all event classes. */

public synchronized void unregister(Object subscriber) {

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

if (subscribedTypes != null) {

for (Class<?> eventType : subscribedTypes) {

unsubscribeByEventType(subscriber, eventType);

}

typesBySubscriber.remove(subscriber);

} else {

学习宝典

对我们开发者来说,一定要打好基础,随时准备战斗。不论寒冬是否到来,都要把自己的技术做精做深。虽然目前移动端的招聘量确实变少了,但中高端的职位还是很多的,这说明行业只是变得成熟规范起来了。竞争越激烈,产品质量与留存就变得更加重要,我们进入了技术赋能业务的时代。

不论遇到什么困难,都不应该成为我们放弃的理由!

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我针对Android程序员,我这边给大家整理了一套学习宝典!包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
(subscriber);

} else {

学习宝典

对我们开发者来说,一定要打好基础,随时准备战斗。不论寒冬是否到来,都要把自己的技术做精做深。虽然目前移动端的招聘量确实变少了,但中高端的职位还是很多的,这说明行业只是变得成熟规范起来了。竞争越激烈,产品质量与留存就变得更加重要,我们进入了技术赋能业务的时代。

不论遇到什么困难,都不应该成为我们放弃的理由!

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我针对Android程序员,我这边给大家整理了一套学习宝典!包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

[外链图片转存中…(img-yCwjLPif-1715428093127)]

【算法合集】

[外链图片转存中…(img-8HIWISKg-1715428093129)]

【延伸Android必备知识点】

[外链图片转存中…(img-LfLpfwKa-1715428093130)]

【Android部分高级架构视频学习资源】
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值