[EventBus源码解析] EventBus.post 方法详述
前情概要
上一篇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 方法详述的更多相关文章
- [EventBus源码解析] EventBus.register 方法详述
前情概要 在上一篇中,介绍了EventBus的基本使用方法,以及一部分进阶技巧.本篇及以后的几篇blog将会集中解析EventBus.java,看看作者是如何优雅地实现这个看似简单的事件分发/接收机制 ...
- EventBus源码解析 源码阅读记录
EventBus源码阅读记录 repo地址: greenrobot/EventBus EventBus的构造 双重加锁的单例. static volatile EventBus defaultInst ...
- 【Android】EventBus 源码解析
EventBus 源码解析 本文为 Android 开源项目实现原理解析 中 EventBus 部分项目地址:EventBus,分析的版本:ccc2771,Demo 地址:EventBus Demo分 ...
- Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean
Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Sprin ...
- Android EventBus源码解析 带你深入理解EventBus
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus ...
- 源码解析-EventBus
示例使用 时序图 源码解读 EventBus 使用 官网定义:EventBus 是一个使用 Java 写的观察者模式,解耦的 Android 开源库.EventBus 只需要几行代码即可解耦简化代码, ...
- 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
- [Java多线程]-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
- EventBus源码解析
用例 本文主要按照如下例子展开: //1. 新建bus对象,默认仅能在主线程上对消息进行调度 Bus bus = new Bus(); // maybe singleton //2. 新建类A(sub ...
随机推荐
- 简单的线性分类——MATLAB,python3实现
看李政轩老师讲的Kernel,讲的非常好!前面有几道作业题,用MATLAB简单做了下,不知道对不对,错误之处还请指出. 题目是这样的. 一.MATLAB版本: clear; clc % 生成train ...
- gulp ---攻略一
根据项目需要可能会出连载 项目需要现在用gulp进行js的质量检测.合并.压缩.发布,未来需要进行sass的编译.合并.压缩,html.img的压缩以及md5戳.reload等功能,暂时先测试js的质 ...
- Unity3D 使用C#指针unsafe
Unsafe code requires the `unsafe' command line option to be specified 在Unity开发中,如果涉及到指针的使用,需要自己定义预处理 ...
- 基于GRPC+consul通信的服务化框架(转)
原文:http://blog.csdn.net/yeyincai/article/details/51470475 -.背景 谈论服务化框架的时候,我们首先先了解这些概念:SOA.ESB.OSGi.s ...
- Python 面向对象(初级篇) (转)
概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发"更快更好更强..." 面 ...
- django1.9.6 使用 DjangoUeditor (python3.5)
DjangoUeditor https://github.com/zhangfisher/DjangoUeditor 1 DjangoUeditor 安装 pip install DjangoUedi ...
- JSBinding / About JSComponent and Serialization
About JSComponent JSCompnent is a normal Unity script. It inherits from JSSerializer and JSSerialize ...
- zend guard6的使用
1.生成key edit->preferences->license Keys->generate 2.新建product license文件 3.新建Zend Guard项目文件 ...
- 031. aps.net中数据绑定控件两种添加自动编号的方法
前端HTML代码: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Defaul ...
- 类似于C# using() java 语法
From : https://www.infoq.com/news/2010/08/arm-blocks try(Jedis jedis = jedisPool.getResource()){ S ...