开始分析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方法分析完了,大致流程总结一下:
-
找到被注册者类中的所有的订阅方法。
-
遍历订阅方法,找到EventBus中eventType对应的订阅列表,然后根据当前订阅者和订阅方法创建一个新的订阅加入到订阅列表。
-
找到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移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
尾声
在我的博客上很多朋友都在给我留言,需要一些系统的面试高频题目。之前说过我的复习范围无非是个人技术博客还有整理的笔记,考虑到笔记是手写版不利于保存,所以打算重新整理并放到网上,时间原因这里先列出面试问题,题解详见:
展示学习笔记
3949927)]
[外链图片转存中…(img-XQLohER7-1711933949927)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-opTnQUr2-1711933949927)]
尾声
在我的博客上很多朋友都在给我留言,需要一些系统的面试高频题目。之前说过我的复习范围无非是个人技术博客还有整理的笔记,考虑到笔记是手写版不利于保存,所以打算重新整理并放到网上,时间原因这里先列出面试问题,题解详见:
[外链图片转存中…(img-aJClqmG4-1711933949928)]
展示学习笔记
[外链图片转存中…(img-Ou8jxHV7-1711933949928)]
[外链图片转存中…(img-eiF3ytcu-1711933949928)]