EventBus框架库代码走读,android音频框架

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

PostingThreadState postingState = currentPostingThreadState.get();

List eventQueue = postingState.eventQueue;

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 {

while (!eventQueue.isEmpty()) {

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

}

} finally {

postingState.isPosting = false;

postingState.isMainThread = false;

}

}

}

public void postSticky(Object event) {

synchronized (stickyEvents) {

stickyEvents.put(event.getClass(), event);

}

// Should be posted after it is putted, in case the subscriber wants to remove immediately

post(event);

}

如上postSticky(Object event)的实质是post了一个stickyEvents,而真正的post(Object event)方法里,currentPostingThreadState是一个ThreadLocal类型的,里面存储了PostingThreadState;PostingThreadState包含了一个eventQueue和一些标志位;eventQueue.add(event);就是把事件放入eventQueue队列,然后while循环遍历eventQueue通过postSingleEvent(eventQueue.remove(0), postingState);语句分发事件;那继续看下这条语句的实现:

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

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

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

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

最后

我这里整理了一份完整的学习思维以及Android开发知识大全PDF,有需要的同学可以自行领取。

资料获取方式:Android完整知识学习体系路线

当然实践出真知,即使有了学习线路也要注重实践,学习过的内容只有结合实操才算是真正的掌握。

lOuSZ2-1711392016377)]
[外链图片转存中…(img-1a9FLKTo-1711392016377)]
[外链图片转存中…(img-mIRpuq5u-1711392016378)]
[外链图片转存中…(img-XP3IKpqP-1711392016378)]

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

最后

我这里整理了一份完整的学习思维以及Android开发知识大全PDF,有需要的同学可以自行领取。

[外链图片转存中…(img-jLo9hI1G-1711392016379)]

资料获取方式:Android完整知识学习体系路线

当然实践出真知,即使有了学习线路也要注重实践,学习过的内容只有结合实操才算是真正的掌握。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值