博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android EventBus源码解析
阅读量:5863 次
发布时间:2019-06-19

本文共 25814 字,大约阅读时间需要 86 分钟。

 项目地址 :https://github.com/greenrobot/EventBus

这个项目个人感觉就是为了解决回调事件过多的,比方说A函数在做完以后 要调用b类的c函数,那我们通常的做法就是 定义一个接口 然后再A函数所属的类里面注册这个接口。

然后a函数做完以后 直接调用这个接口即可。但是这种方法写多了以后确实很麻烦,于是EventBus就是用来解决这种场景的。

和以往一样,我们只解析他的源码,如果你要学习他的用法请自行谷歌。

我们就从register函数开始说起。

1  private synchronized void register(Object subscriber, boolean sticky, int priority) {2         //这个list就是方法的集合3         List
subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());4 //这个循环的目的就是为了用 方法对象 来构造 Subscription对象5 for (SubscriberMethod subscriberMethod : subscriberMethods) {6 subscribe(subscriber, subscriberMethod, sticky, priority);7 }8 }

首先来看一下SubscriberMethod这个类,

1 /* 2  * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); 5  * you may not use this file except in compliance with the License. 6  * You may obtain a copy of the License at 7  * 8  *      http://www.apache.org/licenses/LICENSE-2.0 9  *10  * Unless required by applicable law or agreed to in writing, software11  * distributed under the License is distributed on an "AS IS" BASIS,12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13  * See the License for the specific language governing permissions and14  * limitations under the License.15  */16 package de.greenrobot.event;17 18 import java.lang.reflect.Method;19 20 import android.util.Log;21 22 /**23  * 这个类就是描述方法用的24  */25 final class SubscriberMethod {26     final Method method;27     final ThreadMode threadMode;28     final Class
eventType;29 /** Used for efficient comparison */30 /**31 * 这个methodString 实际上就是用来描述SubscriberMethod对象的,尤其是在重写的equals方法里 起到关键的作用32 * 就类似于这种结构33 * com.example.administrator.eventbustest.ItemDetailFragment#onEventMainThread(com.example.administrator.eventbustest.Item34 *其实也很好理解就是 包名+类名#方法名(参数的类型35 * 注意这里参数的类型也是全路径名 包名+类名36 */37 String methodString;38 39 SubscriberMethod(Method method, ThreadMode threadMode, Class
eventType) {40 this.method = method;41 this.threadMode = threadMode;42 this.eventType = eventType;43 }44 45 @Override46 public boolean equals(Object other) {47 if (other instanceof SubscriberMethod) {48 checkMethodString();49 SubscriberMethod otherSubscriberMethod = (SubscriberMethod) other;50 otherSubscriberMethod.checkMethodString();51 // Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c652 return methodString.equals(otherSubscriberMethod.methodString);53 } else {54 return false;55 }56 }57 58 private synchronized void checkMethodString() {59 if (methodString == null) {60 // Method.toString has more overhead, just take relevant parts of the method61 StringBuilder builder = new StringBuilder(64);62 builder.append(method.getDeclaringClass().getName());63 builder.append('#').append(method.getName());64 builder.append('(').append(eventType.getName());65 methodString = builder.toString();66 }67 }68 69 @Override70 public int hashCode() {71 return method.hashCode();72 }73 }

然后我们来看看这个SubscriberMethod对象组成的集合 是怎么构造出来的。

1 List
findSubscriberMethods(Class
subscriberClass) { 2 String key = subscriberClass.getName(); 3 List
subscriberMethods; 4 synchronized (methodCache) { 5 subscriberMethods = methodCache.get(key); 6 } 7 8 if (subscriberMethods != null) { 9 return subscriberMethods;10 }11 subscriberMethods = new ArrayList
();12 Class
clazz = subscriberClass;13 HashSet
eventTypesFound = new HashSet
();14 StringBuilder methodKeyBuilder = new StringBuilder();15 while (clazz != null) {16 String name = clazz.getName();17 //这个地方判断如果是这些类,那么就直接跳出这个while循环18 //注意name的值 也是包名+类名,所以这里就是过滤掉基础的sdk的那些方法19 //如果你有引用其他公共lib库的话 你也可以过滤他们的包,20 if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {21 // Skip system classes, this just degrades performance22 break;23 }24 25 // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)26 Method[] methods = clazz.getDeclaredMethods();27 for (Method method : methods) {28 String methodName = method.getName();29 Log.e("burning", "methodName == " + methodName);30 //只有那些以onEvent开头的方法才是我们需要的31 if (methodName.startsWith(ON_EVENT_METHOD_NAME)) {32 int modifiers = method.getModifiers();33 //注意这个地方判断方法属性的技巧 与 操作34 if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {35 Class
[] parameterTypes = method.getParameterTypes();36 //如果参数只有一个37 if (parameterTypes.length == 1) {38 String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length());39 //取ThreadMode40 ThreadMode threadMode;41 if (modifierString.length() == 0) {42 threadMode = ThreadMode.PostThread;43 } else if (modifierString.equals("MainThread")) {44 threadMode = ThreadMode.MainThread;45 } else if (modifierString.equals("BackgroundThread")) {46 threadMode = ThreadMode.BackgroundThread;47 } else if (modifierString.equals("Async")) {48 threadMode = ThreadMode.Async;49 } else {50 if (skipMethodVerificationForClasses.containsKey(clazz)) {51 continue;52 } else {53 throw new EventBusException("Illegal onEvent method, check for typos: " + method);54 }55 }56 Class
eventType = parameterTypes[0];57 methodKeyBuilder.setLength(0);58 methodKeyBuilder.append(methodName);59 methodKeyBuilder.append('>').append(eventType.getName());60 //onEventMainThread>java.lang.String61 //methodKey就是上面的形式,可以看出来是方法名>参数 的格式62 String methodKey = methodKeyBuilder.toString();64 //这个地方先去这个hashset里面add这个key,当然了,如果你这个hashset里面已经有这个key65 //那必然是add不成功的,只有add成功返回true以后括号内的代码才会得到执行66 if (eventTypesFound.add(methodKey)) {67 // Only add if not already found in a sub class68 //这个地方就是构造SubscriberMethod对象放到list里 准备返回69 subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType));70 }71 }72 } else if (!skipMethodVerificationForClasses.containsKey(clazz)) {73 Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + "."74 + methodName);75 }76 }77 }78 //这里注意还在大的while循环内,所以你传进去的类自己查完一遍方法以后 还会去找他的父类继续查询方法79 //一直遍历到父类为 那些java android开头的基类为止!80 clazz = clazz.getSuperclass();81 82 }83 if (subscriberMethods.isEmpty()) {84 throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called "85 + ON_EVENT_METHOD_NAME);86 } else {87 synchronized (methodCache) {88 methodCache.put(key, subscriberMethods);89 }90 return subscriberMethods;91 }92 }

然后我们来看看register函数里面 5-6行 那个循环遍历做了什么

首先我们看看这个循环调用的方法:

1 /** 2      * @param subscriber       方法所述的类的 包名+类名 3      * @param subscriberMethod 4      * @param sticky 5      * @param priority 6      */ 7     private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) { 8         //这个eventtype就是方法的参数的类名 9         Class
eventType = subscriberMethod.eventType;10 11 CopyOnWriteArrayList
subscriptions = subscriptionsByEventType.get(eventType);12 Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);13 if (subscriptions == null) {14 subscriptions = new CopyOnWriteArrayList
();15 subscriptionsByEventType.put(eventType, subscriptions);16 } else {17 if (subscriptions.contains(newSubscription)) {18 throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "19 + eventType);20 }21 }22 23 // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again)24 // subscriberMethod.method.setAccessible(true);25 //这个就是优先级高的位置在前面26 int size = subscriptions.size();27 for (int i = 0; i <= size; i++) {28 if (i == size || newSubscription.priority > subscriptions.get(i).priority) {29 subscriptions.add(i, newSubscription);30 break;31 }32 }33 34 List
> subscribedEvents = typesBySubscriber.get(subscriber);35 if (subscribedEvents == null) {36 subscribedEvents = new ArrayList
>();37 typesBySubscriber.put(subscriber, subscribedEvents);38 }39 subscribedEvents.add(eventType);40 41 if (sticky) {42 43 if (eventInheritance) {44 // Existing sticky events of all subclasses of eventType have to be considered.45 // Note: Iterating over all events may be inefficient with lots of sticky events,46 // thus data structure should be changed to allow a more efficient lookup47 // (e.g. an additional map storing sub classes of super classes: Class -> List
).48 Set
, Object>> entries = stickyEvents.entrySet();49 for (Map.Entry
, Object> entry : entries) {50 Class
candidateEventType = entry.getKey();51 if (eventType.isAssignableFrom(candidateEventType)) {52 Object stickyEvent = entry.getValue();53 checkPostStickyEventToSubscription(newSubscription, stickyEvent);54 }55 }56 } else {57 Object stickyEvent = stickyEvents.get(eventType);58 checkPostStickyEventToSubscription(newSubscription, stickyEvent);59 }60 }61 }

10-13行 我们可以看出来 这个函数 主要是为了构造subscription这个list对象。

/**     * 这个map 存储方法的地方 key就是eventType,value就是copyOnWriteArrayList value就是方法的一切     */    private final Map
, CopyOnWriteArrayList
> subscriptionsByEventType;

我们可以看看这个类是什么

1 /** 2  * 这个类里面包含有SubscriberMethod类对象, 3  * subscriber 4  */ 5 final class Subscription { 6     //这个实际上就是描述方法所属的类的 7     final Object subscriber; 8     //描述方法的类 9     final SubscriberMethod subscriberMethod;10     //优先级11     final int priority;12     /**13      * Becomes false as soon as {
@link EventBus#unregister(Object)} is called, which is checked by queued event delivery14 * {
@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.15 */16 volatile boolean active;17 18 Subscription(Object subscriber, SubscriberMethod subscriberMethod, int priority) {19 this.subscriber = subscriber;20 this.subscriberMethod = subscriberMethod;21 this.priority = priority;22 active = true;23 }24 25 @Override26 public boolean equals(Object other) {27 if (other instanceof Subscription) {28 Subscription otherSubscription = (Subscription) other;29 return subscriber == otherSubscription.subscriber30 && subscriberMethod.equals(otherSubscription.subscriberMethod);31 } else {32 return false;33 }34 }35 36 @Override37 public int hashCode() {38 return subscriber.hashCode() + subscriberMethod.methodString.hashCode();39 }40 }

所以总结起来,SubscriberMethod 就是对方法的描述,而我们的SubscriberMethod 实际上就是Subscription的子集,Subscription除了有描述方法的对象以外,还有这个方法所属的类,

而我们的register方法总体来说 就是先通过findSubscriberMethods方法 取得我们注册类(就是你register调用的时候传的this)所需要的的那些方法(注意不是每个方法都需要 只选择自己需要的)

然后把这些方法 做一个list,最后再通过便利这个list : 用每一个SubscriberMethod 对象和这个方法所需的类(包名+类名) 来构造出一个Subscription对象,然后把这个对象

存储在SubscriptionsByEventType里,注意这个map的key 实际上就是eventType,而value则代表方法的list,换句话说。

这个SubscriptionsByEventType 是一个键值对,它的key 实际上就是我们的类名,value则是这个类里面我们需要存储的方法的list!

这就是register的大致流程,我们再来看看post 流程即可。

1  /** 2      * Posts the given event to the event bus. 3      */ 4     public void post(Object event) { 5         PostingThreadState postingState = currentPostingThreadState.get(); 6         //这个地方可以看出来是每次有人调用post方法的时候 都会从postingState取出这个队列,然后把这个事件放到这个队列里 7         List eventQueue = postingState.eventQueue; 8         eventQueue.add(event); 9 10         //这个判断isPosting 主要是为了保证同一时间只能有一个线程在处理括号体里的内容11         //currentPostingThreadState 是用threadlocal来构造的 所以保证了同步性12         if (!postingState.isPosting) {13             postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();14             postingState.isPosting = true;15             if (postingState.canceled) {16                 throw new EventBusException("Internal error. Abort state was not reset");17             }18             try {19                 while (!eventQueue.isEmpty()) {20                     //队列不为空就处理21                     postSingleEvent(eventQueue.remove(0), postingState);22                 }23             } finally {24                 postingState.isPosting = false;25                 postingState.isMainThread = false;26             }27         }28     }

先看看第5行的postingState是什么

1  /** 2      * 静态类,里面除了有一个队列以外,还有几个标志位,以及一个Subscription 3      */ 4     final static class PostingThreadState { 5         final List eventQueue = new ArrayList(); 6         boolean isPosting; 7         boolean isMainThread; 8         Subscription subscription; 9         Object event;10         boolean canceled;11     }

这个地方就能看出来,我们每次调用post 都是往eventQueue里面添加一个事件,而12行开始则是从队列里面

取事件来处理,注意12行开始 一次性只能允许一个线程使用~同步的

然后继续看是怎么处理的。

1  /** 2      * @param event        方法的参数的类名 3      * @param postingState 4      * @throws Error 5      */ 6     private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { 7        8         Class
eventClass = event.getClass(); 9 boolean subscriptionFound = false;10 11 if (eventInheritance) {12 List
> eventTypes = lookupAllEventTypes(eventClass);13 int countTypes = eventTypes.size();14 for (int h = 0; h < countTypes; h++) {15 Class
clazz = eventTypes.get(h);16 //这个地方就是取出Subscription对象的的所有信息!发消息也是在这个函数里发送的17 subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);18 }19 } else {20 subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);21 }22 if (!subscriptionFound) {23 if (logNoSubscriberMessages) {24 Log.d(TAG, "No subscribers registered for event " + eventClass);25 }26 if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&27 eventClass != SubscriberExceptionEvent.class) {28 post(new NoSubscriberEvent(this, event));29 }30 }31 }

继续跟进去

1 private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class
eventClass) { 2 CopyOnWriteArrayList
subscriptions; 3 synchronized (this) { 4 subscriptions = subscriptionsByEventType.get(eventClass); 5 } 6 if (subscriptions != null && !subscriptions.isEmpty()) { 7 for (Subscription subscription : subscriptions) { 8 postingState.event = event; 9 postingState.subscription = subscription;10 boolean aborted = false;11 try {12 //这个地方就是真正发消息的地方了13 postToSubscription(subscription, event, postingState.isMainThread);14 aborted = postingState.canceled;15 } finally {16 postingState.event = null;17 postingState.subscription = null;18 postingState.canceled = false;19 }20 if (aborted) {21 break;22 }23 }24 return true;25 }26 return false;27 }

可以看出来 2-6行 就是从我们register流程里存储的键值对里 把我们存放的方法给取出来。,

取出来以后 就可以反射调用他们的方法了

1   /** 2      * 这个类就是反射执行方法 并且是最终执行回调方法的地方 3      * 4      * @param subscription 5      * @param event 6      * @param isMainThread 7      */ 8     private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { 9         switch (subscription.subscriberMethod.threadMode) {10             case PostThread:11                 invokeSubscriber(subscription, event);12                 break;13             case MainThread:14                 if (isMainThread) {15                     invokeSubscriber(subscription, event);16                 } else {17                     mainThreadPoster.enqueue(subscription, event);18                 }19                 break;20             case BackgroundThread:21                 if (isMainThread) {22                     backgroundPoster.enqueue(subscription, event);23                 } else {24                     invokeSubscriber(subscription, event);25                 }26                 break;27             case Async:28                 asyncPoster.enqueue(subscription, event);29                 break;30             default:31                 throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);32         }33     }

 

13-18行 这个case 如果是主线程,那么就直接反射方法,如果不是的话 则要放到主线程handler里执行。

1  private final HandlerPoster mainThreadPoster;
1  //这个就是主线程handler初始化2         mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
1 /* 2  * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); 5  * you may not use this file except in compliance with the License. 6  * You may obtain a copy of the License at 7  * 8  *      http://www.apache.org/licenses/LICENSE-2.0 9  *10  * Unless required by applicable law or agreed to in writing, software11  * distributed under the License is distributed on an "AS IS" BASIS,12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13  * See the License for the specific language governing permissions and14  * limitations under the License.15  */16 package de.greenrobot.event;17 18 import android.os.Handler;19 import android.os.Looper;20 import android.os.Message;21 import android.os.SystemClock;22 23 final class HandlerPoster extends Handler {24 25     private final PendingPostQueue queue;26     private final int maxMillisInsideHandleMessage;27     private final EventBus eventBus;28     private boolean handlerActive;29 30     HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {31         super(looper);32         this.eventBus = eventBus;33         this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;34         queue = new PendingPostQueue();35     }36 37     void enqueue(Subscription subscription, Object event) {38         PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);39         synchronized (this) {40             queue.enqueue(pendingPost);41             if (!handlerActive) {42                 handlerActive = true;43                 if (!sendMessage(obtainMessage())) {44                     throw new EventBusException("Could not send handler message");45                 }46             }47         }48     }49 50     @Override51     public void handleMessage(Message msg) {52         boolean rescheduled = false;53         try {54             long started = SystemClock.uptimeMillis();55             while (true) {56                 PendingPost pendingPost = queue.poll();57                 if (pendingPost == null) {58                     synchronized (this) {59                         // Check again, this time in synchronized60                         pendingPost = queue.poll();61                         if (pendingPost == null) {62                             handlerActive = false;63                             return;64                         }65                     }66                 }67                 eventBus.invokeSubscriber(pendingPost);68                 long timeInMethod = SystemClock.uptimeMillis() - started;69                 if (timeInMethod >= maxMillisInsideHandleMessage) {70                     if (!sendMessage(obtainMessage())) {71                         throw new EventBusException("Could not send handler message");72                     }73                     rescheduled = true;74                     return;75                 }76             }77         } finally {78             handlerActive = rescheduled;79         }80     }81 }

 

51-77行 就是我们实际最终调用的地方。

 

同样的 我们在看看20-26行的这个background这个case

1 final class BackgroundPoster implements Runnable { 2  3     private final PendingPostQueue queue; 4     private final EventBus eventBus; 5  6     private volatile boolean executorRunning; 7  8     BackgroundPoster(EventBus eventBus) { 9         this.eventBus = eventBus;10         queue = new PendingPostQueue();11     }12 13     public void enqueue(Subscription subscription, Object event) {14         PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);15         synchronized (this) {16             queue.enqueue(pendingPost);17             if (!executorRunning) {18                 executorRunning = true;19                 eventBus.getExecutorService().execute(this);20             }21         }22     }23 24     @Override25     public void run() {26         try {27             try {28                 while (true) {29                     PendingPost pendingPost = queue.poll(1000);30                     if (pendingPost == null) {31                         synchronized (this) {32                             // Check again, this time in synchronized33                             pendingPost = queue.poll();34                             if (pendingPost == null) {35                                 executorRunning = false;36                                 return;37                             }38                         }39                     }40                     eventBus.invokeSubscriber(pendingPost);41                 }42             } catch (InterruptedException e) {43                 Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);44             }45         } finally {46             executorRunning = false;47         }48     }

一看就知道 他是runnable对象 必然是在后台 在子线程内执行,同时他也是一次性只能做一次操作,完成一个事件,

最后我们来看看Async这个case:

1 /* 2  * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); 5  * you may not use this file except in compliance with the License. 6  * You may obtain a copy of the License at 7  * 8  *      http://www.apache.org/licenses/LICENSE-2.0 9  *10  * Unless required by applicable law or agreed to in writing, software11  * distributed under the License is distributed on an "AS IS" BASIS,12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13  * See the License for the specific language governing permissions and14  * limitations under the License.15  */16 package de.greenrobot.event;17 18 19 /**20  * Posts events in background.21  * 22  * @author Markus  并发执行任务,在线程池内执行23  */24 class AsyncPoster implements Runnable {25 26     private final PendingPostQueue queue;27     private final EventBus eventBus;28 29     AsyncPoster(EventBus eventBus) {30         this.eventBus = eventBus;31         queue = new PendingPostQueue();32     }33 34     public void enqueue(Subscription subscription, Object event) {35         PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);36         queue.enqueue(pendingPost);37         eventBus.getExecutorService().execute(this);38     }39 40     @Override41     public void run() {42         PendingPost pendingPost = queue.poll();43         if(pendingPost == null) {44             throw new IllegalStateException("No pending post available");45         }46         eventBus.invokeSubscriber(pendingPost);47     }48 49 }

这个地方和background相同的就是也是在非主线程,在子线程内执行,但是这个地方是在线程池内执行,可以并发执行多个任务,

而我们的background 则一次性只能执行一个任务,这是2者之间的区别。

 

转载于:https://www.cnblogs.com/punkisnotdead/p/4794151.html

你可能感兴趣的文章
域名跳转
查看>>
Flex有提示功能的TextInput输入框
查看>>
kickstart与pxe自动安装linux
查看>>
使用document.write输出覆盖HTML问题
查看>>
第二十四天 代码块与构造方法私有化
查看>>
MySQL命令行--导入导出数据库
查看>>
必看!决定蓝领薪酬高低的因素
查看>>
我的友情链接
查看>>
《分布式对象存储》作者手把手教你写 GO 语言单元测试!
查看>>
springmvc 流程
查看>>
规则引擎配置器简单理解
查看>>
零基础,CCNA自学资料
查看>>
浏览器宽高
查看>>
系统被恶意修改,请从正确渠道获取系统安装程序 解决办法
查看>>
OpenERP —— 下一代ERP
查看>>
iptables规则配置
查看>>
docker对镜像的相关操作
查看>>
对于undotbs01.dbf文件太大的处理办法
查看>>
HTTP缓慢拒绝服务***
查看>>
C# & .NET 1.0-4.0
查看>>