Android源码分析之EventBus框架

秒速五厘米 2023-02-14 02:36 55阅读 0赞

1 EventBus简介

1.1 什么是EventBus?

EventBus是Android和java的发布/订阅事件总线。

1.2 作用

事件总线是对发布-订阅模式的一种实现,它是一种集中式事件处理机制,允许不同的组件之间彼此通信,而又不需要相互依赖,达到解耦的目的。

1.3 优点

(1)简单Android组件之间的通信,避免了Android四大组件复杂的生命周期处理;
(2)在Android四大组件间,以及线程间传递大数据时的唯一选择。因为序列化大数据进行传递时,是十分耗时缓慢的,用EventBus是最优解法;
(3)使用class传递数据,可以携带各种各样的数据,摆脱了用Bundle传递list和数组的麻烦;
(4)清晰明了的主子线程,让你的代码更为简洁;

1.4 缺点

(1)EventBus可以大量解耦项目,但是滥用它,会产生一个非常危险的后果:需要定义大量的常量或者新的实体类来区分接收者,管理EventBus的消息类别将会让你很痛苦;
(2)不要在非前台组件中使用它,因为将它使用到每一个工具类或者后台业务类,会让数据发送与接收更加复杂。别忘记了Java本身就是面对对象语言,它有接口、抽象可以实现来发送与接收数据。我们可以用各种设计模式,比如观察者模式,来更好的优化与独立自己的业务,不需要依赖EventBus;
(3)EventBus,并不是真正的解耦,不要在独立的模块里使用EventBus来分发。这个模块如果那天要直接放入另外一个项目里,你怎么解耦EventBus? 最好,还是多使用接口与Activity本身的数据传递方式。。

1.5 EventBus2.x与EventBus3.x的版本有哪些区别呢?(核心)

(1)EventBus2.x使用的是运行时注解,它采用了反射的方式对整个注册的类的所有方法进行扫描来完成注册,因而会对性能有一定影响
(2)EventBus3.x使用的是编译时注解,Java文件会编译成.class文件,再对class文件进行打包等一系列处理在编译成.class文件时,EventBus会使用EventBusAnnotationProcessor注解处理器读取@Subscribe()注解并解析、处理其中的信息,然后生成Java类来保存所有订阅者的订阅信息。这样就创建出了对文件或类的索引关系,并将其编入到apk中
(3)从EventBus3.0开始使用了对象池缓存减少了创建对象的开销

1.6 关键原理?(核心)

(1)register(Object object): 将所在类作为订阅者,框架会通过反射机制获取所有方法以及其参数,并将订阅者和订阅的方法以及其参数保存到Map中,key为Object,value为Subscription类型的ArrayList,下次从Map中获取。

(2)post(Object event):去遍历所有已经注册事件的订阅者们(即是Map中的key值),然后在根据订阅者对象找到它内部被注解方法(onEvent()),再匹配“被注解方法的参数类型”和“发布者发送的事件类型”是否是同一类型或者父类,就进行反射调用。线程切换用handler和线程池结合runnable进行切换。。

(3)postSticky(Object event): 最后还是调用的post()方法,只是多加了一个添加到粘滞Map中(Map, Object> stickyEvents)步骤;每次调用register(this)时,会检查粘滞Map中是否有订阅对象,然后进行发送;粘滞事件接收后一定要记得移除。

2 EventBus使用3步骤

(1)定义事件

  1. public class MessageEvent {
  2. public final String message;
  3. public MessageEvent(String message) {
  4. this.message = message;
  5. }
  6. }

(2)准备订阅者

  1. @Override
  2. public void onStart() {
  3. super.onStart();
  4. EventBus.getDefault().register(this);
  5. }
  6. @Override
  7. public void onStop() {
  8. EventBus.getDefault().unregister(this);
  9. super.onStop();
  10. }
  11. // 这个方法将在MessageEvent被发布时被调用(在Toast的UI线程中)
  12. @Subscribe (threadMode = ThreadMode.MAIN)
  13. public void onMessageEvent(MessageEvent event) {
  14. Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
  15. }
  16. // 这个方法将在SomeOtherEvent发布时被调用
  17. @Subscribe
  18. public void handleSomethingElse(SomeOtherEvent event) {
  19. doSomethingWith(event);
  20. }

(3)发布事件

  1. EventBus.getDefault().post(new MessageEvent("Hello everyone!"));

(4)学习链接
如何开始与EventBus在3个步骤

3 EventBus原理

3.1 最核心的原理

利用了subscriptionsByEventType这个重要的HashMap对象,将订阅者们,即接收事件的方法存储在这个列表,发布事件的时候在列表中查询出相对应的方法并执行。

  1. Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;

3.2 EventBus框架原理

在这里插入图片描述

3.2.1 关键对象分析

(1)Publisher是发布者:通过post()方法将消息事件Event发布到事件总线;

(2)EventBus是事件总线: 核心模块;

(3)Subscriber是订阅者:收到事件总线发下来的消息,即onEvent方法被执行。注意参数类型必须和发布者发布的参数一致;

3.2.2 关键方法的分析

(1)register(Object object): 将所在类作为订阅者,框架会通过反射机制获取所有方法以及其参数,并将订阅者和订阅的方法以及其参数保存到Map中,key为Object,value为Subscription类型的ArrayList,下次从Map中获取。

(2)post(Object event):去遍历所有已经注册事件的订阅者们(即是Map中的key值),然后在根据订阅者对象找到它内部被注解方法(onEvent()),再匹配“被注解方法的参数类型”和“发布者发送的事件类型”是否是同一类型或者父类,就进行反射调用。线程切换用handler和线程池结合runnable进行切换。。

(3)postSticky(Object event): 最后还是调用的post()方法,只是多加了一个添加到粘滞Map中(Map, Object> stickyEvents)步骤;每次调用register(this)时,会检查粘滞Map中是否有订阅对象,然后进行发送;粘滞事件接收后一定要记得移除。

4 造轮子的方式分析EventBus原理

4.1 基本实体类

  1. // 订阅者类的方法实体
  2. public class SubscriberMethod {
  3. /** 回调方法 */
  4. public Method method;
  5. /** 线程模式 */
  6. public ThreadMode threadMode;
  7. /** 方法中的参数 */
  8. public Class<?> eventType;
  9. /** 是否是粘滞事件 */
  10. public final boolean sticky;
  11. public SubscriberMethod(Method method, ThreadMode threadMode, Class<?> eventType, boolean sticky) {
  12. this.method = method;
  13. this.threadMode = threadMode;
  14. this.eventType = eventType;
  15. this.sticky = sticky;
  16. }
  17. }
  18. // 包装了订阅者+订阅者类的方法的对象
  19. public class Subscription {
  20. public final Object subscriber;
  21. public final SubscriberMethod subscriberMethod;
  22. Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
  23. this.subscriber = subscriber;
  24. this.subscriberMethod = subscriberMethod;
  25. }
  26. @Override
  27. public boolean equals(Object other) {
  28. if (other instanceof Subscription) {
  29. Subscription otherSubscription = (Subscription) other;
  30. return subscriber == otherSubscription.subscriber
  31. && subscriberMethod.equals(otherSubscription.subscriberMethod);
  32. } else {
  33. return false;
  34. }
  35. }
  36. @Override
  37. public int hashCode() {
  38. return subscriber.hashCode() + subscriberMethod.eventType.hashCode();
  39. }
  40. }
  41. // 包装了订阅者+订阅者类的方法的对象 + 事件对象
  42. public class PendingPost {
  43. public Object event;
  44. public Subscription subscription;
  45. public PendingPost(Object event, Subscription subscription) {
  46. this.event = event;
  47. this.subscription = subscription;
  48. }
  49. }

4.2 辅助类

  1. // 方法执行的线程
  2. public enum ThreadMode {
  3. /**
  4. * 订阅者将在发布事件的同一线程中被直接调用。这是默认值。事件传递意味着开销最小,因为它完全避免了线程切换。
  5. * 因此,对于可以在很短的时间内完成而不需要主线程的简单任务,推荐使用这种模式。使用此模式的事件处理程序必须快速返回,
  6. * 以避免阻塞可能是主线程的发布线程。
  7. */
  8. POSTING,
  9. /**
  10. * 订阅者将在Android的主线程(UI线程)中被调用。如果发布线程是主线程、订阅方方法将被直接调用,阻塞发布线程。
  11. * 否则事件正在排队等待交付(非阻塞)。使用此模式的订阅者必须快速返回,以避免阻塞主线程。
  12. */
  13. MAIN,
  14. /**
  15. * 订阅者将在后台线程中被调用。如果发布线程不是主线程,订阅方方法将在发布线程中直接调用。
  16. * 如果提交线程是主线程,则EventBus使用单个线程后台线程,它将按顺序交付其所有事件。
  17. * 使用此模式的订户应尝试这样做快速返回,避免阻塞后台线程。
  18. */
  19. BACKGROUND
  20. }
  21. // 注解类,只有被注解订阅的方法才会被添加到集合中
  22. @Target(ElementType.METHOD)
  23. @Retention(RetentionPolicy.RUNTIME)
  24. public @interface Subscribe {
  25. /** 线程模式 */
  26. ThreadMode threadMode() default ThreadMode.POSTING;
  27. /** 如果为true,则post最近的粘滞事件 */
  28. boolean sticky() default false;
  29. }
  30. // 判断是否是主线程,通常在Android上使用Android的主线程
  31. public interface MainThreadSupport {
  32. boolean isMainThread();
  33. Poster createPoster(EventBus eventBus);
  34. class AndroidHandlerMainThreadSupport implements MainThreadSupport {
  35. private final Looper looper;
  36. public AndroidHandlerMainThreadSupport(Looper looper) {
  37. this.looper = looper;
  38. }
  39. @Override
  40. public boolean isMainThread() {
  41. return looper == Looper.myLooper();
  42. }
  43. @Override
  44. public Poster createPoster(EventBus eventBus) {
  45. return new HandlerPoster(eventBus, looper);
  46. }
  47. }
  48. }

4.3 线程切换发布事件类

  1. // post事件接口
  2. interface Poster {
  3. /**
  4. * 为特定订阅加入要发布的事件队列
  5. *
  6. * @param subscription 订阅将会收到事件的订阅
  7. * @param event 事件将会发布给订阅者.
  8. */
  9. void enqueue(Subscription subscription, Object event);
  10. }
  11. // 主线程中post事件
  12. public class HandlerPoster extends Handler implements Poster {
  13. private final LinkedList<PendingPost> queue;
  14. private final EventBus eventBus;
  15. private boolean handlerActive;
  16. protected HandlerPoster(EventBus eventBus, Looper looper) {
  17. super(looper);
  18. this.eventBus = eventBus;
  19. this.queue = new LinkedList<>();
  20. }
  21. public void enqueue(Subscription subscription, Object event) {
  22. synchronized (this) {
  23. PendingPost pendingPost = new PendingPost(event, subscription);
  24. queue.offer(pendingPost);
  25. if (!handlerActive) {
  26. handlerActive = true;
  27. if (!sendMessage(obtainMessage())) {
  28. Log.e(EventBus.TAG, "Could not send handler message");
  29. }
  30. }
  31. }
  32. }
  33. @Override
  34. public void handleMessage(Message msg) {
  35. boolean rescheduled = false;
  36. try {
  37. while (true) {
  38. PendingPost pendingPost = queue.poll();
  39. if (pendingPost == null) {
  40. synchronized (this) {
  41. // 再次检查,这次是同步的
  42. pendingPost = queue.poll();
  43. if (pendingPost == null) {
  44. handlerActive = false;
  45. return;
  46. }
  47. }
  48. }
  49. eventBus.invokeSubscriber(pendingPost.subscription, pendingPost.event);
  50. rescheduled = true;
  51. }
  52. } finally {
  53. handlerActive = rescheduled;
  54. }
  55. }
  56. }
  57. // 子线程中post事件
  58. public class BackgroundPoster implements Runnable, Poster {
  59. private final LinkedList<PendingPost> queue;
  60. private final EventBus eventBus;
  61. private volatile boolean executorRunning;
  62. BackgroundPoster(EventBus eventBus) {
  63. this.eventBus = eventBus;
  64. queue = new LinkedList<>();
  65. }
  66. public void enqueue(Subscription subscription, Object event) {
  67. synchronized (this) {
  68. PendingPost pendingPost = new PendingPost(event, subscription);
  69. queue.offer(pendingPost);
  70. if (!executorRunning) {
  71. executorRunning = true;
  72. eventBus.getExecutorService().execute(this);
  73. }
  74. }
  75. }
  76. @Override
  77. public void run() {
  78. try {
  79. while (true) {
  80. PendingPost pendingPost = queue.poll();
  81. if (pendingPost == null) {
  82. synchronized (this) {
  83. // 再次检查,这次是同步的
  84. pendingPost = queue.poll();
  85. if (pendingPost == null) {
  86. executorRunning = false;
  87. return;
  88. }
  89. }
  90. }
  91. eventBus.invokeSubscriber(pendingPost.subscription, pendingPost.event);
  92. }
  93. } finally {
  94. executorRunning = false;
  95. }
  96. }
  97. }

4.4 EventBus

  1. /**
  2. * EventBus发布/订阅事件总线
  3. */
  4. public class EventBus {
  5. public static String TAG = "Tag_EventBus";
  6. private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
  7. private static volatile EventBus defaultInstance;
  8. /**
  9. * 判断是否是主线程
  10. */
  11. private final MainThreadSupport mainThreadSupport;
  12. private final Poster mainThreadPoster;
  13. private final BackgroundPoster backgroundPoster;
  14. /**
  15. * 接收 订阅者+订阅者类的方法的对象 存储在这个列表中
  16. */
  17. private final Map<Object, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
  18. /**
  19. * 接收订阅者存储在这个列表中
  20. */
  21. private final Map<Object, List<Class<?>>> typesBySubscriber;
  22. /**
  23. * 接收粘滞事件订阅者存储在这个列表中
  24. */
  25. private final Map<Class<?>, Object> stickyEvents;
  26. private EventBus() {
  27. this.mainThreadSupport = new MainThreadSupport.AndroidHandlerMainThreadSupport(Looper.getMainLooper());;
  28. this.mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
  29. this.backgroundPoster = new BackgroundPoster(this);
  30. this.subscriptionsByEventType = new HashMap<>();
  31. this.typesBySubscriber = new HashMap<>();
  32. this.stickyEvents = new ConcurrentHashMap<>();
  33. }
  34. /**
  35. * 使用一个进程范围的EventBus实例为应用程序提供方便的单例
  36. */
  37. public static EventBus getDefault() {
  38. if (defaultInstance == null) {
  39. synchronized (EventBus.class) {
  40. if (defaultInstance == null) {
  41. defaultInstance = new EventBus();
  42. }
  43. }
  44. }
  45. return defaultInstance;
  46. }
  47. /**
  48. * 注册订阅者
  49. *
  50. * @param subscriber
  51. */
  52. public void register(Object subscriber) {
  53. List<Subscription> subscriptions = findSubscriberMethods(subscriber);
  54. synchronized (this) {
  55. for (Subscription subscription : subscriptions) {
  56. subscribe(subscriber, subscription.subscriberMethod);
  57. }
  58. }
  59. }
  60. /**
  61. * 订阅:Must be called in synchronized block
  62. *
  63. * @param subscriber
  64. * @param subscriberMethod
  65. */
  66. private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
  67. Class<?> eventType = subscriberMethod.eventType;
  68. Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
  69. CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(subscriber);
  70. if (subscriptions == null) {
  71. subscriptions = findSubscriberMethods(subscriber);
  72. subscriptionsByEventType.put(subscriber, subscriptions);
  73. }
  74. List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
  75. if (subscribedEvents == null) {
  76. subscribedEvents = new ArrayList<>();
  77. typesBySubscriber.put(subscriber, subscribedEvents);
  78. }
  79. subscribedEvents.add(eventType);
  80. // 如果是粘滞事件
  81. if (subscriberMethod.sticky) {
  82. Object stickyEvent = stickyEvents.get(eventType);
  83. if (stickyEvent != null) {
  84. // 如果订阅者试图中止事件,它将失败(在发布状态中不跟踪事件)
  85. postToSubscription(newSubscription, stickyEvent, isMainThread());
  86. }
  87. }
  88. }
  89. /**
  90. * 遍历订阅者类的方法
  91. * 通过反射获取订阅者+订阅者类的方法对象的集合,找到被SubScribe注解订阅的方法,如:onEvent()
  92. *
  93. * @param subscriber
  94. * @return
  95. */
  96. private CopyOnWriteArrayList<Subscription> findSubscriberMethods(Object subscriber) {
  97. CopyOnWriteArrayList<Subscription> subscriptions = new CopyOnWriteArrayList<>();
  98. Class<?> clazz = subscriber.getClass();
  99. // 通过getDeclaredMethods()来获取类中所有方法而并不是通过getMethods(),由于前者只反射当前类的方法(不包括隐式继承的父类方法),所以前者的效率较后者更高些
  100. Method[] methods = clazz.getDeclaredMethods();
  101. while (clazz != null) {
  102. // 找父类的时候 需要先判断一下是否是 系统级别的父类
  103. String name = clazz.getName();
  104. if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
  105. break;
  106. }
  107. for (Method method : methods) {
  108. // 找到被SubScribe注解订阅的方法
  109. Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
  110. if (subscribeAnnotation == null) {
  111. continue;
  112. }
  113. // 判断带有Subscribe注解方法中的参数类型
  114. Class<?>[] types = method.getParameterTypes();
  115. if (types.length != 1) {
  116. Log.e(EventBus.TAG, "EventBus只接受一个参数");
  117. continue;
  118. }
  119. ThreadMode threadMode = subscribeAnnotation.threadMode();
  120. SubscriberMethod subscriberMethod = new SubscriberMethod(method, threadMode, types[0], subscribeAnnotation.sticky());
  121. Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
  122. subscriptions.add(newSubscription);
  123. }
  124. clazz = clazz.getSuperclass();
  125. }
  126. return subscriptions;
  127. }
  128. /**
  129. * 发布事件
  130. * 匹配"被SubScribe注解订阅的方法的参数"和"发布者发布的对象"一致,即可分发Event
  131. *
  132. * @param event
  133. */
  134. public void post(final Object event) {
  135. // 直接循环 Map 里面的方法 找到"被SubScribe注解订阅的方法的参数"和"发布者发布的对象"一致的方法
  136. Set<Object> subscribers = subscriptionsByEventType.keySet();
  137. // 遍历所有订阅者对象,包括接口
  138. for (final Object subscriber : subscribers) {
  139. List<Subscription> subscriptions = subscriptionsByEventType.get(subscriber);
  140. if (subscriptions == null) {
  141. return;
  142. }
  143. // 遍历此订阅者+订阅者类的方法对象的所有方法
  144. for (final Subscription subscription : subscriptions) {
  145. // 类Class1所对应的类信息是不是Class2所对应的类信息的父类或接口,或类Class1和Class2是否相同
  146. if (subscription.subscriberMethod.eventType.isAssignableFrom(event.getClass())) {
  147. postToSubscription(subscription, event, isMainThread());
  148. }
  149. }
  150. }
  151. }
  152. private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
  153. switch (subscription.subscriberMethod.threadMode) {
  154. case POSTING:
  155. invokeSubscriber(subscription, event);
  156. break;
  157. case MAIN:
  158. if (isMainThread) {
  159. invokeSubscriber(subscription, event);
  160. } else {
  161. mainThreadPoster.enqueue(subscription, event);
  162. }
  163. break;
  164. case BACKGROUND:
  165. if (isMainThread) {
  166. backgroundPoster.enqueue(subscription, event);
  167. } else {
  168. invokeSubscriber(subscription, event);
  169. }
  170. break;
  171. default:
  172. throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
  173. }
  174. }
  175. /**
  176. * 执行订阅者订阅的方法,参数是event
  177. *
  178. * @param subscription
  179. * @param event
  180. */
  181. public void invokeSubscriber(Subscription subscription, Object event) {
  182. try {
  183. subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
  184. } catch (InvocationTargetException e) {
  185. e.printStackTrace();
  186. } catch (IllegalAccessException e) {
  187. throw new IllegalStateException("Unexpected exception", e);
  188. }
  189. }
  190. /**
  191. * 将给定事件发布到事件总线并持有该事件(因为它具有粘性)。事件类型的最新粘贴事件保存在内存中,
  192. * 供订阅者使用{@link Subscribe#sticky()}将来访问。
  193. */
  194. public void postSticky(Object event) {
  195. synchronized (stickyEvents) {
  196. stickyEvents.put(event.getClass(), event);
  197. }
  198. // 是否应在发布后发布,以防订阅者想立即删除
  199. post(event);
  200. }
  201. /**
  202. * 获取给定类型的最新粘贴事件
  203. *
  204. * @see #postSticky(Object)
  205. */
  206. public <T> T getStickyEvent(Class<T> eventType) {
  207. synchronized (stickyEvents) {
  208. return eventType.cast(stickyEvents.get(eventType));
  209. }
  210. }
  211. /**
  212. * 删除并获取给定事件类型的最近粘贴事件
  213. *
  214. * @see #postSticky(Object)
  215. */
  216. public <T> T removeStickyEvent(Class<T> eventType) {
  217. synchronized (stickyEvents) {
  218. return eventType.cast(stickyEvents.remove(eventType));
  219. }
  220. }
  221. /**
  222. * 删除与给定事件相等的粘滞事件
  223. *
  224. * @return true 如果事件匹配并且粘性事件被删除
  225. */
  226. public boolean removeStickyEvent(Object event) {
  227. synchronized (stickyEvents) {
  228. Class<?> eventType = event.getClass();
  229. Object existingEvent = stickyEvents.get(eventType);
  230. if (event.equals(existingEvent)) {
  231. stickyEvents.remove(eventType);
  232. return true;
  233. } else {
  234. return false;
  235. }
  236. }
  237. }
  238. /**
  239. * 删除所有粘滞事件
  240. */
  241. public void removeAllStickyEvents() {
  242. synchronized (stickyEvents) {
  243. stickyEvents.clear();
  244. }
  245. }
  246. /**
  247. * 反注册:移除订阅者和它的事件方法
  248. *
  249. * @param subscriber
  250. */
  251. public void unregister(Object subscriber) {
  252. List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
  253. if (subscribedTypes != null) {
  254. subscriptionsByEventType.remove(subscriber);
  255. typesBySubscriber.remove(subscriber);
  256. subscribedTypes.clear();
  257. } else {
  258. Log.e(EventBus.TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
  259. }
  260. }
  261. /**
  262. * 检查当前线程是否在主线程中运行。如果没有主线程支持(例如非android),总是返回“true”。
  263. * 在这种情况下,主线程订阅者总是在发布线程中调用,而后台订阅者总是从后台海报中调用
  264. */
  265. public boolean isMainThread() {
  266. return mainThreadSupport == null || mainThreadSupport.isMainThread();
  267. }
  268. /**
  269. * 获取线程池
  270. *
  271. * @return
  272. */
  273. public ExecutorService getExecutorService() {
  274. return DEFAULT_EXECUTOR_SERVICE;
  275. }
  276. }

4.5 实践

  1. // 定义事件
  2. public class MessageEvent {
  3. public String name;
  4. public String num;
  5. public MessageEvent(String name, String num) {
  6. this.name = name;
  7. this.num = num;
  8. }
  9. }
  10. // EventBus发布事件页面
  11. public class EventBusPostActivity extends AppCompatActivity {
  12. @Override
  13. protected void onCreate(Bundle savedInstanceState) {
  14. super.onCreate(savedInstanceState);
  15. setContentView(R.layout.activity_eventbus_post);
  16. }
  17. /**
  18. * 在子线程中发布事件
  19. */
  20. public void postInThread(View view) {
  21. new Thread(new Runnable() {
  22. @Override
  23. public void run() {
  24. // 在子线程中发布事件
  25. Log.d(EventBus.TAG, "子线程中发布 threadName :" + Thread.currentThread().getName());
  26. EventBus.getDefault().post(new MessageEvent("小小", "123"));
  27. }
  28. }).start();
  29. }
  30. /**
  31. * 在主线程中发布事件
  32. */
  33. public void postInMain(View view) {
  34. Log.d(EventBus.TAG, "主线程中发布 threadName :" + Thread.currentThread().getName());
  35. EventBus.getDefault().post(new MessageEvent("大大","456"));
  36. }
  37. /**
  38. * 发布粘性事件
  39. *
  40. * @param view
  41. */
  42. public void postSticky(View view) {
  43. Log.d(EventBus.TAG, "发布 postSticky threadName :" + Thread.currentThread().getName());
  44. // 粘性事件,在发送事件之后再订阅该事件也能收到。并且,粘性事件会保存在内存中,每次进入都会去内存中查找获取最新的粘性事件,除非你手动解除注册。
  45. EventBus.getDefault().postSticky(new MessageEvent("发布 postSticky:Hello everyone!", "789"));
  46. }
  47. /**
  48. * 手动获取和删除粘性事件
  49. *
  50. * @param view
  51. */
  52. public void removeStickyEvent(View view) {
  53. MessageEvent stickyEvent = EventBus.getDefault().getStickyEvent(MessageEvent.class);
  54. if(stickyEvent != null) {
  55. EventBus.getDefault().removeStickyEvent(stickyEvent);
  56. }
  57. }
  58. /**
  59. * 注册
  60. *
  61. * @param view
  62. */
  63. public void register(View view) {
  64. EventBus.getDefault().register(this);
  65. }
  66. /**
  67. * 反注册
  68. *
  69. * @param view
  70. */
  71. public void unRegister(View view) {
  72. EventBus.getDefault().unregister(this);
  73. }
  74. /**
  75. * 当MessageEvent被发布时将调用此方法
  76. *
  77. * 默认情况下,EventBus捕获从订阅者方法抛出的异常,并发送不强制要求处理的SubscriberExceptionEvent。
  78. * Caused by: EventBusException: Subscriber class ...EventBusActivity and its super classes have no public methods with the @Subscribe annotation
  79. *
  80. * @param event
  81. */
  82. @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
  83. public void onEventBus(MessageEvent event) {
  84. Log.e(EventBus.TAG,"onEventBus + 接收到EventBus事件:" + event.name);
  85. }
  86. /**
  87. * EventBus 是为已经存在的activity传递消息,而且订阅者必须要注册且不能被注销了,
  88. * 如果你在onStop里面注销了,栈中虽然有这个activity,但是EventBus并没有被注册,所以也接收不到消息,
  89. */
  90. // @Override
  91. // public void onStop() {
  92. // EventBus.getDefault().unregister(this);
  93. // super.onStop();
  94. // }
  95. @Override
  96. public void onDestroy() {
  97. EventBus.getDefault().unregister(this);
  98. super.onDestroy();
  99. }
  100. }
  101. D/Tag_EventBus: 主线程中发布 threadName :main
  102. D/Tag_EventBus: onEvent: com.example.rxjava_example.MessageEvent@48b101b
  103. D/Tag_EventBus: onEvent threadName :main
  104. D/Tag_EventBus: onMessageEvent: com.example.rxjava_example.MessageEvent@48b101b
  105. D/Tag_EventBus: onMessageEvent threadName :pool-1-thread-1
  106. D/Tag_EventBus: 发布 postSticky threadName :main
  107. E/Tag_EventBus: onEventBus + 接收到EventBus事件:发布 postStickyHello everyone!
  108. D/Tag_EventBus: onEvent: com.example.rxjava_example.MessageEvent@a595ef6
  109. D/Tag_EventBus: onEvent threadName :main
  110. D/Tag_EventBus: onMessageEvent: com.example.rxjava_example.MessageEvent@a595ef6
  111. D/Tag_EventBus: onMessageEvent threadName :pool-1-thread-1

5 EventBus源码分析

5.1 初始化

(1)EventBus.getDefault():通过单例模式获得EventBus对象

  1. public static EventBus getDefault() {
  2. EventBus instance = defaultInstance;
  3. if (instance == null) {
  4. synchronized (EventBus.class) {
  5. instance = EventBus.defaultInstance;
  6. if (instance == null) {
  7. instance = EventBus.defaultInstance = new EventBus();
  8. }
  9. }
  10. }
  11. return instance;
  12. }

(2)通过构建EventBusBuilder来设置参数

  1. private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
  2. // 保存事件参数类和Subscription List的Map
  3. private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
  4. // 保存注册对象和事件参数类
  5. private final Map<Object, List<Class<?>>> typesBySubscriber;
  6. // 粘性事件
  7. private final Map<Class<?>, Object> stickyEvents;
  8. public class EventBusBuilder {
  9. private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
  10. // 异常的设置
  11. boolean logSubscriberExceptions = true;
  12. boolean logNoSubscriberMessages = true;
  13. boolean sendSubscriberExceptionEvent = true;
  14. boolean sendNoSubscriberEvent = true;
  15. boolean throwSubscriberException;
  16. boolean eventInheritance = true;
  17. // 是否忽略生成的Index,默认为false,不忽略
  18. boolean ignoreGeneratedIndex;
  19. boolean strictMethodVerification;
  20. ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;
  21. List<Class<?>> skipMethodVerificationForClasses;
  22. List<SubscriberInfoIndex> subscriberInfoIndexes;
  23. EventBusBuilder() {
  24. }
  25. }
  26. public EventBus() {
  27. this(DEFAULT_BUILDER);
  28. }
  29. EventBus(EventBusBuilder builder) {
  30. subscriptionsByEventType = new HashMap<>();
  31. typesBySubscriber = new HashMap<>();
  32. stickyEvents = new ConcurrentHashMap<>();
  33. // 主线程发送器
  34. mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
  35. // 后台线程发送器
  36. backgroundPoster = new BackgroundPoster(this);
  37. // 异步线程发送器
  38. asyncPoster = new AsyncPoster(this);
  39. indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
  40. subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
  41. builder.strictMethodVerification, builder.ignoreGeneratedIndex);
  42. // 异常设置
  43. logSubscriberExceptions = builder.logSubscriberExceptions;
  44. logNoSubscriberMessages = builder.logNoSubscriberMessages;
  45. sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
  46. sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
  47. throwSubscriberException = builder.throwSubscriberException;
  48. eventInheritance = builder.eventInheritance;
  49. executorService = builder.executorService;
  50. }

EventBus初始化的步骤,直观上看用到单例模式和Builder模式,将构造参数给分离了出来,实际上还用到了策略模式,其中Builder中有些参数用于代码执行的策略,就说,你传的参数不一样,我执行的方式不一样,像ignoreGeneratedIndex作用就是让EventBus如何查找出订阅方法的策略

(3)最重要的是一些缓存对象:

  1. subscriptionsByEventType : 内部是一个Map集合,可以根据 EventType 查找订阅事件;
  2. typesBySubscriber : 根据我们的订阅对象找到 EventType
  3. stickyEvents : 粘滞事件的缓存;
  4. 事件投递者 : mainThreadPoster, backgroundPoster, asyncPoster根据订阅注解ThreadMode去选择不同的投递者,不同投递者投递事件,接收函数会执行在不同的线程中;
  5. subscriberMethodFinder :查找方法用的,内部维护了一个订阅方法的集合。

5.2 注册register()

  1. // Eventbus.java:
  2. public void register(Object subscriber) {
  3. // 获得注册对象的class
  4. Class<?> subscriberClass = subscriber.getClass();
  5. // 5.2.1 查找订阅者被订阅的方法
  6. List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
  7. synchronized (this) {
  8. for (SubscriberMethod subscriberMethod : subscriberMethods) {
  9. // 5.2.2 订阅
  10. subscribe(subscriber, subscriberMethod);
  11. }
  12. }
  13. }

在这里插入图片描述

5.2.1 findSubscriberMethods()找出一个SubscriberMethod的集合

当我们调用register(this)的时候就把订阅者给传了进来,主要就两个步骤:第一个findSubscriberMethods()找出一个SubscriberMethod的集合,然后就遍历 SubscriberMethod的集合去订阅事件,我们先看**findSubscriberMethods()**里面到底做了什么,返回的是什么?

  1. // SubscriberMethodFinder.java:
  2. List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
  3. // 5.2.1.1 从方法缓存中查找
  4. List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
  5. // 找到直接返回
  6. if (subscriberMethods != null) {
  7. return subscriberMethods;
  8. }
  9. // 是否忽略生成的Index(高级用法会通过编译时注解生成,这里不会)
  10. // ignoreGeneratedIndex默认为false,进入下面的代码
  11. if (ignoreGeneratedIndex) {
  12. // 5.2.1.3 通过反射获取方法
  13. subscriberMethods = findUsingReflection(subscriberClass);
  14. } else {
  15. // 5.2.1.2 通过subscriberInfo获取方法
  16. subscriberMethods = findUsingInfo(subscriberClass);
  17. }
  18. // 如果没有找到方法,抛出异常(常见的这个异常,没有@Subscribe方法)
  19. if (subscriberMethods.isEmpty()) {
  20. throw new EventBusException("Subscriber " + subscriberClass+ " and its super classes have no public methods with the @Subscribe annotation");
  21. } else {
  22. // 5.2.1.4 找到订阅方法后放入缓存,以免下次继续重新查找
  23. METHOD_CACHE.put(subscriberClass, subscriberMethods);
  24. return subscriberMethods;
  25. }
  26. }

5.2.1.1 首先,从缓存METHOD_CACHE中检查是否拥有当前订阅类,找到直接返回;

5.2.1.4 最后,找到订阅方法后放入缓存METHOD_CACHE中,以免下次重新查找订阅方法;

5.2.1.3 通过反射获取方法,ignoreGeneratedIndex为true,那会执行findUsingReflection()方法通过反射来调用

  1. // SubscriberMethodFinder.java
  2. private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
  3. FindState findState = prepareFindState();
  4. findState.initForSubscriber(subscriberClass);
  5. while (findState.clazz != null) {
  6. // 5.2.1.2(3)第3步,进入**findUsingReflectionInSingleClass通过反射来调用**
  7. findUsingReflectionInSingleClass(findState);
  8. findState.moveToSuperclass();
  9. }
  10. return getMethodsAndRelease(findState);
  11. }

findUsingReflectionInSingleClass(findState)的分析请看:5.2.1.2(3)第3步,进入findUsingReflectionInSingleClass通过反射来调用

5.2.1.2 通过subscriberInfo获取方法,ignoreGeneratedIndex默认就是false,那会执行findUsingInfo()方法:

  1. // SubscriberMethodFinder.java:
  2. private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
  3. // 第1步:从池中或创建或使用
  4. FindState findState = prepareFindState();
  5. // 初始化
  6. findState.initForSubscriber(subscriberClass);
  7. while (findState.clazz != null) {
  8. // 第2步:调用getSubscriberInfo查找是否有添加的SubscriberInfoIndex,这个是需要添加编译器支持,
  9. // 并且在编译器自动生成,需要手动添加的,默认是没有添加的
  10. findState.subscriberInfo = getSubscriberInfo(findState);
  11. if (findState.subscriberInfo != null) {
  12. SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
  13. for (SubscriberMethod subscriberMethod : array) {
  14. if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
  15. findState.subscriberMethods.add(subscriberMethod);
  16. }
  17. }
  18. } else {
  19. // 第3步:如果没有找到,通过反射来查找
  20. findUsingReflectionInSingleClass(findState);
  21. }
  22. // 获得其父类
  23. findState.moveToSuperclass();
  24. }
  25. // 第4步:获得方法并释放FindState对象
  26. return getMethodsAndRelease(findState);
  27. }
第1步,通过池取出或创建一个FindState对象,FindState中维护的就是我们对订阅方法查找结果的封装,initForSubscriber()就是将我们的订阅者传给FindState对象
  1. private FindState prepareFindState() {
  2. synchronized (FIND_STATE_POOL) {
  3. for (int i = 0; i < POOL_SIZE; i++) {
  4. FindState state = FIND_STATE_POOL[i];
  5. if (state != null) {
  6. FIND_STATE_POOL[i] = null;
  7. return state;
  8. }
  9. }
  10. }
  11. return new FindState();
  12. }
第3步,进入findUsingReflectionInSingleClass通过反射来调用
  1. // SubscriberMethodFinder.java:
  2. private void findUsingReflectionInSingleClass(FindState findState) {
  3. Method[] methods;
  4. try {
  5. // 1、获得类的方法
  6. methods = findState.clazz.getDeclaredMethods();
  7. } catch (Throwable th) {
  8. methods = findState.clazz.getMethods();
  9. findState.skipSuperClasses = true;
  10. }
  11. for (Method method : methods) {
  12. int modifiers = method.getModifiers();
  13. // 2、如果方法的修饰符是public并且不是 Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC
  14. if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
  15. // 获得参数类型数组
  16. Class<?>[] parameterTypes = method.getParameterTypes();
  17. // 如果参数是一个
  18. if (parameterTypes.length == 1) {
  19. // 判断该方法是否被Subscribe注解修饰
  20. Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
  21. // 如果还有Subscribe注解,则将参数类型
  22. if (subscribeAnnotation != null) {
  23. Class<?> eventType = parameterTypes[0];
  24. // 3、检验下是否之前已经添加了SubscriberMethod对象
  25. if (findState.checkAdd(method, eventType)) {
  26. // 返回false,说明其父类也有这个方法
  27. // 返回true,说明其父类没有这个方法,findState.subscriberMethods中添加SubscriberMethod对象
  28. ThreadMode threadMode = subscribeAnnotation.threadMode();
  29. findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
  30. subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
  31. }
  32. }
  33. } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
  34. // 抛出参数过多的异常
  35. String methodName = method.getDeclaringClass().getName() + "." + method.getName();
  36. throw new EventBusException("@Subscribe method " + methodName +
  37. "must have exactly 1 parameter but has " + parameterTypes.length);
  38. }
  39. } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
  40. // 抛出方法修饰符不正确异常
  41. String methodName = method.getDeclaringClass().getName() + "." + method.getName();
  42. throw new EventBusException(methodName +
  43. " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
  44. }
  45. }
  46. }

(1)反射的3个步骤:

  1. 1、获得类的方法;
  2. 2、遍历类,并且检查:
  3. 1)检查方法修饰符是不是public
  4. 2)检查参数数量是不是等于1
  5. 3)检查方法是否还有Subscribe注解;
  6. 三个条件都满足的话,则需要检查方法和参数类型是否已经存在,是否此方法需要添加threadMode
  7. 3、根据检查结果来判断是否添加SubscriberMethod对象;

(2)添加订阅方法前有个检查checkAdd方法

  1. // SubscriberMethodFinder.java:
  2. boolean checkAdd(Method method, Class<?> eventType) {
  3. // 分两步检查:
  4. // 1. 检查参数类型是不是已经存在
  5. // 2. 通过方法签名(可以说是名称拼接)来判断
  6. Object existing = anyMethodByEventType.put(eventType, method);
  7. // 不存在接收该参数类型的方法
  8. if (existing == null) {
  9. return true;
  10. } else {
  11. // 存在接收该参数类型的方法,这里应该比较少见。应该就是不同的方法但是都有相同的参数
  12. if (existing instanceof Method) {
  13. if (!checkAddWithMethodSignature((Method) existing, eventType)) {
  14. throw new IllegalStateException();
  15. }
  16. // Put any non-Method object to "consume" the existing Method
  17. anyMethodByEventType.put(eventType, this);
  18. }
  19. return checkAddWithMethodSignature(method, eventType);
  20. }
  21. }
  22. // SubscriberMethodFinder.java:
  23. private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
  24. methodKeyBuilder.setLength(0);
  25. methodKeyBuilder.append(method.getName());
  26. methodKeyBuilder.append('>').append(eventType.getName());
  27. // 将方法名和事件类型当作key,来保存方法
  28. String methodKey = methodKeyBuilder.toString();
  29. Class<?> methodClass = method.getDeclaringClass();
  30. Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
  31. // 如果我们保存的是父类,就返回 true
  32. if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
  33. // Only add if not already found in a sub class
  34. return true;
  35. } else {
  36. // 如果是子类,就将传来的方法保存起来,返回 false
  37. subscriberClassByMethodKey.put(methodKey, methodClassOld);
  38. return false;
  39. }
  40. }

这里又做了一个优化,将方法名和事件类型当作key,来保存方法,将传来的方法类型和我们签名的保存的比较;如果我们保存的是父类,就返回true,如果是子类,就将传来的方法保存起来,返回false。这样做的意图是:如果有父类的方法了,就没有必要添加子类的方法了,因为继承会执行到的。

第2步,从subscriberInfoIndexes中查找订阅信息的,在编译期创建索引并找到我们的订阅信息了,不会在运行期做任何事情,所以这个效率是非常高的,这也是EventBus3.0中增加了一个新特性

EventBus提供了一个EventBusAnnotationProcessor注解处理器来在编译期通过读取@Subscribe()注解并解析,处理其中所包含的信息,然后生成java类来保存所有订阅者关于订阅的信息,这样就比在运行时使用反射来获得这些订阅者的信息速度要快。

  1. private SubscriberInfo getSubscriberInfo(FindState findState) {
  2. // 查找FindState的缓存是否有订阅信息,有则直接返回
  3. if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
  4. SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
  5. if (findState.clazz == superclassInfo.getSubscriberClass()) {
  6. return superclassInfo;
  7. }
  8. }
  9. // 从subscriberInfoIndexes中查找订阅信息(EventBusBuilder的subscriberInfoIndexes)
  10. if (subscriberInfoIndexes != null) {
  11. for (SubscriberInfoIndex index : subscriberInfoIndexes) {
  12. SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
  13. if (info != null) {
  14. return info;
  15. }
  16. }
  17. }
  18. return null;
  19. }

(1)在项目的app的build.gradle中添加如下配置:

  1. android {
  2. defaultConfig {
  3. // EventBus processor
  4. javaCompileOptions {
  5. // 注解处理器参数配置
  6. annotationProcessorOptions {
  7. // 配置参数名和值
  8. arguments = [eventBusIndex: 'com.seniorlibs.thirdlib.MyEventBusIndex']
  9. }
  10. }
  11. }
  12. }
  13. dependencies {
  14. implementation fileTree(dir: 'libs', include: ['*.jar'])
  15. // EventBus
  16. api 'org.greenrobot:eventbus:3.2.0'
  17. // EventBus processor
  18. annotationProcessor 'org.greenrobot:eventbus-annotation-processor:3.2.0'
  19. }

(2)然后rebulid,在\build\generated\source\apt\com.seniorlibs.thirdlib\下看到通过注解分析生成的索引类MyEventBusIndex

  1. public class MyEventBusIndex implements SubscriberInfoIndex {
  2. private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;
  3. static {
  4. SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();
  5. putIndex(new SimpleSubscriberInfo(com.seniorlibs.thirdlib.eventbus.EventBusActivity.class, true,
  6. new SubscriberMethodInfo[] {
  7. new SubscriberMethodInfo("onMessageEvent", com.seniorlibs.thirdlib.eventbus.MessageEvent.class,
  8. ThreadMode.MAIN, 0, true),
  9. }));
  10. }
  11. private static void putIndex(SubscriberInfo info) {
  12. SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
  13. }
  14. @Override
  15. public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
  16. SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
  17. if (info != null) {
  18. return info;
  19. } else {
  20. return null;
  21. }
  22. }
  23. }

(3)在Application中通过EventBus初始化,将这个类给传进去:

  1. EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus().register(this);

(4)MyEventBusIndex在初始化时,直接会将订阅者相关信息缓存在Map中,并实现了SubscriberInfoIndex接口,在实现方法getSubscriberInfo中根据订阅类返回对应的订阅者信息。在编译过程中就已经找到我们的订阅信息了,不会在运行期做任何事情,所以这个效率是非常高的。

第4步,获得方法并释放FindState对象:
  1. // SubscriberMethodFinder.java:
  2. private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
  3. // 创建List并返回
  4. List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
  5. // 池回收并将给池中的为空的位置赋值,方便findState下次使用,不需要
  6. findState.recycle();
  7. synchronized (FIND_STATE_POOL) {
  8. for (int i = 0; i < POOL_SIZE; i++) {
  9. if (FIND_STATE_POOL[i] == null) {
  10. FIND_STATE_POOL[i] = findState;
  11. break;
  12. }
  13. }
  14. }
  15. return subscriberMethods;
  16. }

从这里,我们就知道作者设计FindState池的初心了,解析完了之后,将订阅方法赋给List集合,再回收FindState,继续接收解析,内存没有半点浪费

5.2.2 需要订阅的方法已经找到,接下来将方法订阅-subscribe()

  1. // EventBus.java
  2. private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
  3. // 参数类型
  4. Class<?> eventType = subscriberMethod.eventType;
  5. // 根据订阅者和订阅方法构造一个订阅事件
  6. Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
  7. // subscriptionsByEventType是根据eventType去查找subscriptions集合
  8. CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
  9. // 看看缓存中有没有,没有则放进缓存
  10. if (subscriptions == null) {
  11. subscriptions = new CopyOnWriteArrayList<>();
  12. subscriptionsByEventType.put(eventType, subscriptions);
  13. } else {
  14. // 已经存在的话,抛出异常
  15. if (subscriptions.contains(newSubscription)) {
  16. throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
  17. }
  18. }
  19. // 遍历订阅事件,找到比subscriptions中订阅事件大的优先级,然后插入。就可以根据优先级依次投递事件了
  20. int size = subscriptions.size();
  21. for (int i = 0; i <= size; i++) {
  22. if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
  23. subscriptions.add(i, newSubscription);
  24. break;
  25. }
  26. }
  27. // typesBySubscriber是根据订阅者去查找EventType的缓存,并保存起来。为的是unregister(this),根据this去解绑事件
  28. List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
  29. if (subscribedEvents == null) {
  30. subscribedEvents = new ArrayList<>();
  31. typesBySubscriber.put(subscriber, subscribedEvents);
  32. }
  33. // 添加新的参数类型
  34. subscribedEvents.add(eventType);
  35. // 如果是粘性,就立刻处理
  36. if (subscriberMethod.sticky) {
  37. // 构造是默认为true
  38. if (eventInheritance) {
  39. // EventType的子类也应该考虑
  40. Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
  41. for (Map.Entry<Class<?>, Object> entry : entries) {
  42. Class<?> candidateEventType = entry.getKey();
  43. // 参数类型是存储的父类或者相同
  44. if (eventType.isAssignableFrom(candidateEventType)) {
  45. Object stickyEvent = entry.getValue();
  46. // 如果有值的话发送事件
  47. // 意味着如果粘性事件的参数类型存在,并且对应的值也存在的话将发送事件
  48. checkPostStickyEventToSubscription(newSubscription, stickyEvent);
  49. }
  50. }
  51. } else {
  52. Object stickyEvent = stickyEvents.get(eventType);
  53. checkPostStickyEventToSubscription(newSubscription, stickyEvent);
  54. }
  55. }
  56. }

订阅其实里面就做了两件事:
(1)第1件事:遍历订阅方法和订阅者,订阅者和订阅方法的参数类型保存起来,封装到subscriptionsByEventType和typesBySubscriber,至于这两个对象是干什么的呢?subscriptionsByEventType是我们投递订阅事件的时候,就是根据订阅方法参数类型EventType找到订阅事件subscriberMethod,从而去分发处理事件typesBySubscriber是在调用unregister(this) 的时候,根据订阅者subscriber找到订阅方法参数类型EventType,又根据EventType找到订阅事件,从而解绑
在这里插入图片描述
(2)第2件事:如果是粘性事件的话,就立马投递并执行

5.3 发布post

  1. public void post(Object event) {
  2. // 使用ThreadLocal来确保每个线程都维护了一个投递状态PostingThreadState
  3. PostingThreadState postingState = currentPostingThreadState.get();
  4. // 获取事件队列
  5. List<Object> eventQueue = postingState.eventQueue;
  6. // 将最新的事件添加到队尾
  7. eventQueue.add(event);
  8. // 如果当前没有进行中的事件
  9. if (!postingState.isPosting) {
  10. // 设置当前线程是否为主线程
  11. postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
  12. // 设置正在发送状态
  13. postingState.isPosting = true;
  14. if (postingState.canceled) {
  15. throw new EventBusException("Internal error. Abort state was not reset");
  16. }
  17. try {
  18. // PostingThreadState是维护了投递的状态,最后循环投递,直到PostingThreadState中的EventQueue为空
  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.3.1 调用postToSubscription()通过策略模式实现线程模式

调用post(Object object) 的方法的时候就执行了上面的代码,PostingThreadState是维护了投递的状态,最后循环投递,直到 PostingThreadState中的EventQueue为空。那么代码最终执行到postToSubscription(),根据ThreadMode去处理事件,通过策略模式实现线程模式

  1. private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
  2. // 根据订阅方法的threadMode来判断如何执行
  3. switch (subscription.subscriberMethod.threadMode) {
  4. // 默认,在哪个线程发送在哪个线程执行
  5. case POSTING:
  6. invokeSubscriber(subscription, event);
  7. break;
  8. // 最终执行在主线程中
  9. case MAIN:
  10. if (isMainThread) {
  11. invokeSubscriber(subscription, event);
  12. } else {
  13. mainThreadPoster.enqueue(subscription, event);
  14. }
  15. break;
  16. // 后台线程
  17. case BACKGROUND:
  18. if (isMainThread) {
  19. backgroundPoster.enqueue(subscription, event);
  20. } else {
  21. invokeSubscriber(subscription, event);
  22. }
  23. break;
  24. // 异步线程
  25. case ASYNC:
  26. asyncPoster.enqueue(subscription, event);
  27. break;
  28. default:
  29. throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
  30. }
  31. }

在这里插入图片描述

5.3.2 主线程模式HandlerPoster

当线程模式是主线程的时候,意味着需要执行的代码在主线程中操作,就是通过反射,直接运行订阅的方法;如果不是主线程,需要mainThreadPoster将订阅事件入队列。一起看看mainThreadPoster的工作原理:

  1. // HandlerPoster.java
  2. public class HandlerPoster extends Handler implements Poster {
  3. private final PendingPostQueue queue;
  4. private final int maxMillisInsideHandleMessage;
  5. private final EventBus eventBus;
  6. private boolean handlerActive;
  7. protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
  8. super(looper);
  9. this.eventBus = eventBus;
  10. this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
  11. queue = new PendingPostQueue();
  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 (!handlerActive) {
  18. handlerActive = true;
  19. if (!sendMessage(obtainMessage())) {
  20. throw new EventBusException("Could not send handler message");
  21. }
  22. }
  23. }
  24. }
  25. @Override
  26. public void handleMessage(Message msg) {
  27. boolean rescheduled = false;
  28. try {
  29. long started = SystemClock.uptimeMillis();
  30. while (true) {
  31. PendingPost pendingPost = queue.poll();
  32. if (pendingPost == null) {
  33. synchronized (this) {
  34. // Check again, this time in synchronized
  35. pendingPost = queue.poll();
  36. if (pendingPost == null) {
  37. handlerActive = false;
  38. return;
  39. }
  40. }
  41. }
  42. eventBus.invokeSubscriber(pendingPost);
  43. long timeInMethod = SystemClock.uptimeMillis() - started;
  44. if (timeInMethod >= maxMillisInsideHandleMessage) {
  45. if (!sendMessage(obtainMessage())) {
  46. throw new EventBusException("Could not send handler message");
  47. }
  48. rescheduled = true;
  49. return;
  50. }
  51. }
  52. } finally {
  53. handlerActive = rescheduled;
  54. }
  55. }
  56. }

其实在EventBus初始化的时候,mainThreadPoster就已经获取主线程的Looper了,就是用到了Android的消息处理机制:Looper、Handler,至于消息队列是自己维护的一个单向的链表。每次向Andorid的主线程Looper投递一个空消息,然后在 HandlerMessage()方法里面从自己维护的队列中取出PendingPost 进行处理。而PendingPost中维护的是订阅事件,EventType 和下一个PendingPost的地址:

  1. final class PendingPost {
  2. private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();
  3. Object event;
  4. Subscription subscription;
  5. PendingPost next;
  6. }

5.3.3 子线程模式BackgroundPoster

  1. // BackgroundPoster.java:
  2. final class BackgroundPoster implements Runnable {
  3. private final PendingPostQueue queue;
  4. private final EventBus eventBus;
  5. private volatile boolean executorRunning;
  6. BackgroundPoster(EventBus eventBus) {
  7. this.eventBus = eventBus;
  8. queue = new PendingPostQueue();
  9. }
  10. public void enqueue(Subscription subscription, Object event) {
  11. PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
  12. synchronized (this) {
  13. // 入队操作
  14. queue.enqueue(pendingPost);
  15. if (!executorRunning) {
  16. executorRunning = true;
  17. // 这里用到了线程池去执行
  18. eventBus.getExecutorService().execute(this);
  19. }
  20. }
  21. }
  22. @Override
  23. public void run() {
  24. try {
  25. try {
  26. // 出队,执行队列中所有的事件
  27. while (true) {
  28. PendingPost pendingPost = queue.poll(1000);
  29. if (pendingPost == null) {
  30. synchronized (this) {
  31. // 再次检测,如果还没有则执行结束
  32. pendingPost = queue.poll();
  33. if (pendingPost == null) {
  34. executorRunning = false;
  35. return;
  36. }
  37. }
  38. }
  39. // 存在PendingPost对象,调用EventBus去执行订阅者订阅的方法
  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. }
  49. }
  50. // executorService的默认值是下面的线程池
  51. public static ExecutorService newCachedThreadPool() {
  52. return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
  53. }

BackgroundPoster这里面维护了一个队列,如果此发送器正在执行,则将此次事件的PendingPost(将要发送的事件)对象加入队列的尾部,在子线程的run方法中通过PendingPostQueue.poll()方法获得第一个PendingPost对象,并且调用eventBus.invokeSubscriber(pendingPost)去执行订阅的方法

5.3.4 最终反射调用方法invokeSubscriber()执行订阅的方法

  1. // EventBus.java:
  2. void invokeSubscriber(PendingPost pendingPost) {
  3. Object event = pendingPost.event;
  4. Subscription subscription = pendingPost.subscription;
  5. PendingPost.releasePendingPost(pendingPost);
  6. if (subscription.active) {
  7. // 如果没有取消注册,这个变量是volatile修饰,每次都会取最新值
  8. // 调用invokeSubscriber方法执行订阅的方法
  9. invokeSubscriber(subscription, event);
  10. }
  11. }
  12. void invokeSubscriber(Subscription subscription, Object event) {
  13. try {
  14. // 执行订阅者订阅的方法,参数是event
  15. subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
  16. } catch (InvocationTargetException e) {
  17. handleSubscriberException(subscription, event, e.getCause());
  18. } catch (IllegalAccessException e) {
  19. throw new IllegalStateException("Unexpected exception", e);
  20. }
  21. }

5.4 反注册unregister()

  1. public synchronized void unregister(Object subscriber) {
  2. List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
  3. if (subscribedTypes != null) {
  4. for (Class<?> eventType : subscribedTypes) {
  5. unsubscribeByEventType(subscriber, eventType);
  6. }
  7. typesBySubscriber.remove(subscriber);
  8. } else {
  9. logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
  10. }
  11. }

**反注册就是通过EventBus中typesBySubscriber这个属性,通过订阅者subscriber去查找订阅事件eventType,然后去一一解绑的。**当然,反注册主要是为了提高效率的,不然订阅的事件太多,非常影响性能。

5.5 新特性-粘滞事件

看订阅中的最后一段代码呢?5.2.2 需要订阅的方法已经找到,接下来将方法订阅-subscribe()

  1. // EventBus.java
  2. // 如果是粘性,就立刻处理
  3. if (subscriberMethod.sticky) {
  4. // 构造是默认为true
  5. if (eventInheritance) {
  6. // EventType的子类也应该考虑
  7. Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
  8. for (Map.Entry<Class<?>, Object> entry : entries) {
  9. Class<?> candidateEventType = entry.getKey();
  10. // 参数类型是存储的父类或者相同
  11. if (eventType.isAssignableFrom(candidateEventType)) {
  12. Object stickyEvent = entry.getValue();
  13. // 如果有值的话发送事件
  14. // 意味着如果粘性事件的参数类型存在,并且对应的值也存在的话将发送事件
  15. checkPostStickyEventToSubscription(newSubscription, stickyEvent);
  16. }
  17. }
  18. } else {
  19. Object stickyEvent = stickyEvents.get(eventType);
  20. checkPostStickyEventToSubscription(newSubscription, stickyEvent);
  21. }
  22. }
  23. private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
  24. if (stickyEvent != null) {
  25. postToSubscription(newSubscription, stickyEvent, isMainThread());
  26. }
  27. }
  28. // 发布粘性事件
  29. public void postSticky(Object event) {
  30. synchronized (stickyEvents) {
  31. stickyEvents.put(event.getClass(), event);
  32. }
  33. post(event);
  34. }
  35. // 手动获取和删除粘性事件
  36. public boolean removeStickyEvent(Object event) {
  37. synchronized (stickyEvents) {
  38. Class<?> eventType = event.getClass();
  39. Object existingEvent = stickyEvents.get(eventType);
  40. if (event.equals(existingEvent)) {
  41. stickyEvents.remove(eventType);
  42. return true;
  43. } else {
  44. return false;
  45. }
  46. }
  47. }

6 优秀的思想和设计

6.1

6.2

7 EventBus面试题解答

7.1

7.2

8 学习链接

Android——EventBus源码分析

EventBus 3.0源码解析

Android主流三方库源码分析(九、深入理解EventBus源码)

EventBus3.0使用及源码分析(包含UML图)

EventBus3.0解析之注解处理器分析

GitHub-EventBus仓库

发表评论

表情:
评论列表 (有 0 条评论,55人围观)

还没有评论,来说两句吧...

相关阅读