前情概要

  上一篇blog我们了解了EventBus中register/unregister的过程,对EventBus如何实现观察者模式有了基本的认识。今天我们来看一下它是如何分发一个特定事件的,即post(Object event)方法。

本篇概述

  EventBus中事件的分发与响应,post 方法。

post 方法

public void post(Object event) {
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> 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;
}
}
}

  postingState(分发状态)具有ThreadLocal属性,包含一个eventQueue,用来保存当前线程分发中的event,在while循环中,逐一调用 postSingleEvent(eventQueue.remove(0), postingState),清空发送队列。

postSingleEvent 方法

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
if (eventInheritance) {
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {
if (logNoSubscriberMessages) {
Log.d(TAG, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) {
post(new NoSubscriberEvent(this, event));
}
}
}

  这个方法用来分发单个事件,如果EventBus支持继承,则分发继承的所有基类事件;若没有找到订阅者,则根据logNoSubscribeMessages、sendNoSubscriberEvent这两个标志位处理相应的逻辑(打日志、发送NoSubscriberEvent事件)。

  再进一步,我们看看 postSingleEventForEventType 方法。

postSingleEventForEventType 方法

  在仔细阅读源代码之前,我们应该大致就能够猜想得到,这一步,理应是遍历该事件类型的订阅者列表,找到对应的订阅者后把事件发送出去;结合之前了解过的EventBus响应事件的四种模式(PostThread, MainThread, BackgroundThread, Async),接下来关注的重点是分发事件时如何处理这一段逻辑。

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}

  通过eventType找到对应的subscriptions后,逐一调用postToSubscription方法,其中对四种事件相应方式进行了处理。最终是通过反射进行了对应方法的调用。

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case PostThread:
invokeSubscriber(subscription, event);
break;
case MainThread:
if (isMainThread) {
invokeSubscriber(subscription, event);
} else {
mainThreadPoster.enqueue(subscription, event);
}
break;
case BackgroundThread:
if (isMainThread) {
backgroundPoster.enqueue(subscription, event);
} else {
invokeSubscriber(subscription, event);
}
break;
case Async:
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}

总结

  分发事件的过程并不复杂,真正核心的一句话就可以概括:根据eventType找到对应的订阅者,通过反射进行具体方法调用。

下期预告

  四种线程模式实现方式解析。

[EventBus源码解析] EventBus.post 方法详述的更多相关文章

  1. [EventBus源码解析] EventBus.register 方法详述

    前情概要 在上一篇中,介绍了EventBus的基本使用方法,以及一部分进阶技巧.本篇及以后的几篇blog将会集中解析EventBus.java,看看作者是如何优雅地实现这个看似简单的事件分发/接收机制 ...

  2. EventBus源码解析 源码阅读记录

    EventBus源码阅读记录 repo地址: greenrobot/EventBus EventBus的构造 双重加锁的单例. static volatile EventBus defaultInst ...

  3. 【Android】EventBus 源码解析

    EventBus 源码解析 本文为 Android 开源项目实现原理解析 中 EventBus 部分项目地址:EventBus,分析的版本:ccc2771,Demo 地址:EventBus Demo分 ...

  4. Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean

    Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Sprin ...

  5. Android EventBus源码解析 带你深入理解EventBus

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus ...

  6. 源码解析-EventBus

    示例使用 时序图 源码解读 EventBus 使用 官网定义:EventBus 是一个使用 Java 写的观察者模式,解耦的 Android 开源库.EventBus 只需要几行代码即可解耦简化代码, ...

  7. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  8. [Java多线程]-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  9. EventBus源码解析

    用例 本文主要按照如下例子展开: //1. 新建bus对象,默认仅能在主线程上对消息进行调度 Bus bus = new Bus(); // maybe singleton //2. 新建类A(sub ...

随机推荐

  1. java 深度探险 java 泛型

    Java泛型(generics)是JDK 5中引入的一个新特性,允许在定义类和接口的时候使用类型参数(type parameter).声明的类型参数在使用时用具体的类型来替换.泛型最主要的应用是在JD ...

  2. 关于uboot和kernel的一些理解

    经过多次的修改和实验,终于能够在mini2440开发板上进行各种uboot和kernel的挂载实验了,在此期间学习到了很多知识,也理解了一些知识1->分区uboot和kernel的分区表要一致u ...

  3. Soufun_News

    using AnfleCrawler.Common; using System; using System.Collections.Generic; using System.ComponentMod ...

  4. Python开发入门与实战12-业务逻辑层

    12. Biz业务层 前面的章节我们把大量的业务函数都放在了views.py里,按照目前这一的写法,当我们编写的系统复杂较高时,我们的views.py将会越来越复杂,大量的业务函数包含其中使其成为一个 ...

  5. iOS开发网络请求——大文件的多线程断点下载

    iOS开发中网络请求技术已经是移动app必备技术,而网络中文件传输就是其中重点了.网络文件传输对移动客户端而言主要分为文件的上传和下载.作为开发者从技术角度会将文件分为小文件和大文件.小文件因为文件大 ...

  6. 集合运算(A-B)U(B-A)

    实质是两个数组的合并(顺序表最好是有序的) #include<iostream> using namespace std; //创建顺序表 void create(int A[],int ...

  7. 点击含下拉菜单的列表/表单按钮:通过JS创建虚拟按钮并点击

    ${JsCode} | Get Element Attribute | XPATH=//table[@class='mnubar']//tr//td//span[text()='${MenuArr[0 ...

  8. 设置ASP.NET页面的运行超时时间详细到单个页面及站点

    这篇文章主要介绍了如何设置ASP.NET页面的运行超时时间,包括全局超时时间.单个站点超时时间.单个页面请求超时时间,需要的朋友可以参考下     全局超时时间 服务器上如果有多个网站,希望统一设置一 ...

  9. 关于asp的运行环境配置

    xp系统的配置方法http://jingyan.baidu.com/article/4f7d571289ac441a201927da.html win7系统的配置方法http://jingyan.ba ...

  10. Ubuntu12.04安装vscode i386

    最近在Ubuntu12.04的32位版本上安装vscode,我下载的是32位deb包,  vscode官网 安装命令 sudo dpkg -i vscode-i386.deb 安装完成没有报错,但是点 ...