EventBus框架库代码走读,Github标星25K+超火的Android实战项目

开始分析EventBus前可以下看下EventBus开源框架的工程目录结构:

这里写图片描述

从上图可以发现,其实EventBus的代码量不是很大,还是很方便入手分析的。

开始分析


通过上一篇基础使用可以发现,使用EventBus框架第一步是得到EventBus实例,那我们就从EventBus类文件的getDefault()方法开始分析。如下:

/** 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()构造方法:

public EventBus() {

this(DEFAULT_BUILDER);

}

EventBus(EventBusBuilder builder) {

subscriptionsByEventType = new HashMap<Class<?>, CopyOnWriteArrayList>();

typesBySubscriber = new HashMap<Object, List<Class<?>>>();

stickyEvents = new ConcurrentHashMap<Class<?>, Object>();

mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);

backgroundPoster = new BackgroundPoster(this);

asyncPoster = new AsyncPoster(this);

subscriberMethodFinder = new SubscriberMethodFinder(builder.skipMethodVerificationForClasses);

logSubscriberExceptions = builder.logSubscriberExceptions;

logNoSubscriberMessages = builder.logNoSubscriberMessages;

sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;

sendNoSubscriberEvent = builder.sendNoSubscriberEvent;

throwSubscriberException = builder.throwSubscriberException;

eventInheritance = builder.eventInheritance;

executorService = builder.executorService;

}

这里的构造方法EventBus(EventBusBuilder builder)使用了建造者模式给EventBus设置一些基本参数标志。这里使用了DEFAULT_BUILDER,也即默认参数。

到这里一个默认的单例模式的EventBus对象实例获取完成。通过这段代码可以发现,我们也可以通过 EventBusBuilder或者EventBus的构造函数新建一个EventBus实例,但是每个新建的EventBus发布和订阅事件都是相互隔离的。

接着继续停留在EventBus类分析,可以看到该类的主要职责就是负责所有对外暴露的API。

按照上一篇的使用例子顺序来看,得到EventBus实例后需要在开始处调运register方法,结束处调运unregister方法,所以我们从register方法开始分析:

public void register(Object subscriber) {

register(subscriber, false, 0);

}

public void register(Object subscriber, int priority) {

register(subscriber, false, priority);

}

public void registerSticky(Object subscriber) {

register(subscriber, true, 0);

}

public void registerSticky(Object subscriber, int priority) {

register(subscriber, true, priority);

}

private synchronized void register(Object subscriber, boolean sticky, int priority) {

List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());

for (SubscriberMethod subscriberMethod : subscriberMethods) {

subscribe(subscriber, subscriberMethod, sticky, priority);

}

}

可以看到EventBus类提供了四个register方法,但是最终都调运了register(Object subscriber, boolean sticky, int priority)方法。

register(Object subscriber, boolean sticky, int priority)方法的三个参数含义如下:

  • subscriber:传入要扫描类的类对象(订阅者)。

  • sticky:是否是粘粘性消息。

  • priority:优先级,优先级越高,在调用的时候会越先调用。

由此可以看出register(Object subscriber),registerSticky(Object subscriber)的默认优先级都是0,其他的register方法可自定义优先级。同理register的方法默认都是不粘粘性的事件,registerSticky的方法没人都是粘粘性的事件。

继续看register(Object subscriber, boolean sticky, int priority)方法,可以发现其中首先执行了List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());语句,这句话就是调运SubscriberMethodFinder类的findSubscriberMethods方法,传入了subscriber 的class,返回一个List<SubscriberMethod>。如下:

List findSubscriberMethods(Class<?> subscriberClass) {

String key = subscriberClass.getName();

List subscriberMethods;

synchronized (methodCache) {

subscriberMethods = methodCache.get(key);

}

if (subscriberMethods != null) {

return subscriberMethods;

}

subscriberMethods = new ArrayList();

Class<?> clazz = subscriberClass;

HashSet eventTypesFound = new HashSet();

StringBuilder methodKeyBuilder = new StringBuilder();

while (clazz != null) {

String name = clazz.getName();

if (name.startsWith(“java.”) || name.startsWith(“javax.”) || name.startsWith(“android.”)) {

// Skip system classes, this just degrades performance

break;

}

// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)

Method[] methods = clazz.getDeclaredMethods();

for (Method method : methods) {

String methodName = method.getName();

if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {

int modifiers = method.getModifiers();

if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {

Class<?>[] parameterTypes = method.getParameterTypes();

if (parameterTypes.length == 1) {

String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());

ThreadMode threadMode;

if (modifierString.length() == 0) {

threadMode = ThreadMode.PostThread;

} else if (modifierString.equals(“MainThread”)) {

threadMode = ThreadMode.MainThread;

} else if (modifierString.equals(“BackgroundThread”)) {

threadMode = ThreadMode.BackgroundThread;

} else if (modifierString.equals(“Async”)) {

threadMode = ThreadMode.Async;

} else {

if (skipMethodVerificationForClasses.containsKey(clazz)) {

continue;

} else {

throw new EventBusException("Illegal onEvent method, check for typos: " + method);

}

}

Class<?> eventType = parameterTypes[0];

methodKeyBuilder.setLength(0);

methodKeyBuilder.append(methodName);

methodKeyBuilder.append(‘>’).append(eventType.getName());

String methodKey = methodKeyBuilder.toString();

if (eventTypesFound.add(methodKey)) {

// Only add if not already found in a sub class

subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));

}

}

} else if (!skipMethodVerificationForClasses.containsKey(clazz)) {

Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + “.”

  • methodName);

}

}

}

clazz = clazz.getSuperclass();

}

if (subscriberMethods.isEmpty()) {

throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "

  • ON_EVENT_METHOD_NAME);

} else {

synchronized (methodCache) {

methodCache.put(key, subscriberMethods);

}

return subscriberMethods;

}

}

上面就是获取传入对象class的方法的方法。其中前半部分是先去缓存查找是否有这个类的记录,如果有直接返回,没有继续执行。当没有时继续走到Method[] methods = clazz.getDeclaredMethods();语句得到该类的所有方法;接着那个大for循环就是遍历这个类匹配符合封装要求的method;其中,if (methodName.startsWith(ON_EVENT_METHOD_NAME))用来判断方法名是不是以“onEvent”开头;接着if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0)用于继续判断是否是public且非static和abstract方法;if (parameterTypes.length == 1)用于继续判断是否是一个参数。如果都复合,才进入封装的部分;接着也比较简单,根据方法的后缀,来确定threadMode,threadMode是个四种情况的枚举类型(前面基础使用一篇解释过四种类型);接着通过subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));把method添加到subscriberMethods列表;接着通过clazz = clazz.getSuperclass();扫描父类的方法;接着while结束,扫描完后通过methodCache.put(key, subscriberMethods);将方法放入缓存,然后返回List<SubscriberMethod>的方法列表(订阅者方法至此查找完成)。

接着继续回到上一级方法:

private synchronized void register(Object subscriber, boolean sticky, int priority) {

List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());

for (SubscriberMethod subscriberMethod : subscriberMethods) {

subscribe(subscriber, subscriberMethod, sticky, priority);

}

}

通过for循环遍历List<SubscriberMethod>里的方法,同时传入suscribe方法。具体如下:

// Must be called in synchronized block

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {

//从订阅方法中拿到订阅事件的类型

Class<?> eventType = subscriberMethod.eventType;

通过订阅事件类型,找到所有的订阅(Subscription)

CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);

//创建一个新的订阅

Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);

if (subscriptions == null) {

//如果该事件目前没有订阅列表,创建并加入该订阅

subscriptions = new CopyOnWriteArrayList();

subscriptionsByEventType.put(eventType, subscriptions);

} else {

//如果有订阅列表,检查是否已经加入过

if (subscriptions.contains(newSubscription)) {

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

  • eventType);

}

}

// Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)

// subscriberMethod.method.setAccessible(true);

int size = subscriptions.size();

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

//根据优先级插入订阅

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

subscriptions.add(i, newSubscription);

break;

}

}

//根据subscriber存储它所有的eventType

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

if (subscribedEvents == null) {

subscribedEvents = new ArrayList<Class<?>>();

typesBySubscriber.put(subscriber, subscribedEvents);

}

//将这个订阅事件加入到订阅者的订阅事件列表中

subscribedEvents.add(eventType);

//判断sticky;如果为true,从stickyEvents中根据eventType去查找有没有stickyEvent,如果有则立即发布去执行。stickyEvent其实就是我们post时的参数

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

}

}

}

到这里register方法分析完了,大致流程总结一下:

  1. 找到被注册者类中的所有的订阅方法。

  2. 遍历订阅方法,找到EventBus中eventType对应的订阅列表,然后根据当前订阅者和订阅方法创建一个新的订阅加入到订阅列表。

  3. 找到EvnetBus中subscriber订阅的事件列表,将eventType加入到这个事件列表。

所以对于任何一个订阅者,我们可以找到它的订阅事件类型列表,通过这个订阅事件类型,可以找到在订阅者中的订阅函数。

既然register函数分析完了,那么接下来就该分析unregister了,成对出现嘛!如下:

/** 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) {

unubscribeByEventType(subscriber, eventType);

}

typesBySubscriber.remove(subscriber);

} else {

Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());

}

}

可以看到,首先获取了subscribe函数中根据subscriber存储它的所有eventType保存到List<Class<?>> subscribedTypes;接着如果存在注册过的type则通过unubscribeByEventType(subscriber, eventType);循环遍历,完事remove掉所有,这样就完成了所有的unregister功能;至于unubscribeByEventType函数如何实现,具体如下:

/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */

private void unubscribeByEventType(Object subscriber, Class<?> eventType) {

List subscriptions = subscriptionsByEventType.get(eventType);

if (subscriptions != null) {

int size = subscriptions.size();

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

Subscription subscription = subscriptions.get(i);

if (subscription.subscriber == subscriber) {

subscription.active = false;

subscriptions.remove(i);

i–;

size–;

}

}

}

}

从上面代码可以看出,原来在register时真正存储EventBus事件的Map是subscriptionsByEventType成员。这里就是循环遍历找出需要unregister的remove掉。至此,整个EventBus的register与unregister函数都分析完毕。

依照前一篇使用来看,进行完register与unregister后剩下的就是post了,那么接下来分析分析post过程,如下:

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

public void post(Object event) {

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

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

尾声

在我的博客上很多朋友都在给我留言,需要一些系统的面试高频题目。之前说过我的复习范围无非是个人技术博客还有整理的笔记,考虑到笔记是手写版不利于保存,所以打算重新整理并放到网上,时间原因这里先列出面试问题,题解详见:


展示学习笔记

3949927)]
[外链图片转存中…(img-XQLohER7-1711933949927)]
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-opTnQUr2-1711933949927)]

尾声

在我的博客上很多朋友都在给我留言,需要一些系统的面试高频题目。之前说过我的复习范围无非是个人技术博客还有整理的笔记,考虑到笔记是手写版不利于保存,所以打算重新整理并放到网上,时间原因这里先列出面试问题,题解详见:

[外链图片转存中…(img-aJClqmG4-1711933949928)]
展示学习笔记
[外链图片转存中…(img-Ou8jxHV7-1711933949928)]
[外链图片转存中…(img-eiF3ytcu-1711933949928)]

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值