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

/**

  • 初始化数据

*/

private void initData() {

EventBus.getDefault().register(this);

}

@Override

protected void onDestroy() {

super.onDestroy();

EventBus.getDefault().unregister(this);

}

}

通过EventBus.getDefault().register(this);方法注册订阅者。

3)发送消息

public class SecondActivity extends Activity {

private TextView message;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_second);

initView();

}

/**

  • 初始化布局组件

*/

private void initView() {

message = findViewById(R.id.message);

message.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

EventBus.getDefault().post(new MyEvent(“1”,“这是从SecondActivity发送过来的消息”));

Toast.makeText(SecondActivity.this, “消息发送成功”, Toast.LENGTH_SHORT).show();

}

});

}

}

通过EventBus.getDefault().post(new MyEvent(“1”,“这是从SecondActivity发送过来的消息”));方法发送消息

源码分析


EventBus的使用先注册订阅者,并实现方法,然后再发送post消息,所以我们分析源码也按照这个顺序来。

1)实例化EventBus

EventBus.getDefault().register(this);

该方法首先获取EventBus实例,然后再注册,源码如下所示:

/** Convenience singleton for apps using a process-wide EventBus instance. */

public static EventBus getDefault() {

if (defaultInstance == null) {

synchronized (EventBus.class) {

if (defaultInstance == null) {

defaultInstance = new EventBus();

}

}

}

return defaultInstance;

}

可以看到,实例化EventBus是个双重锁的单例模式。

接下来看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);

}

学习路线+知识梳理

花了很长时间,就为了整理这张详细的知识路线脑图。当然由于时间有限、能力也都有限,毕竟嵌入式全体系实在太庞大了,包括我那做嵌入式的同学,也不可能什么都懂,有些东西可能没覆盖到,不足之处,还希望小伙伴们一起交流补充,一起完善进步。

这次就分享到这里吧,下篇见
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 24
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值