【EventBus】EventBus 源码解析 ( 事件发送 | 发布线程为 子线程 切换到 主线程 执行订阅方法的过程分析 )
一、EventBus 中主线程支持类
在 EventBus.postToSubscription
方法中 , 如果当前线程是子线程 , 则调用如下方法 , 切换到主线程执行 ;
// 假如发布线程是子线程 , 则将事件加入队列 , 通过 Handler 切换线程执行
mainThreadPoster.enqueue(subscription, event);
mainThreadPoster
是通过 mainThreadSupport.createPoster(this)
创建的 ;
注意 , 创建 mainThreadPoster 时 , 会判定当前线程是否是主线程 , 如果当前线程是主线程 , 才会创建 mainThreadPoster , 否则为空 ;
EventBus 中 mainThreadPoster 相关代码 :
public class EventBus {
// @Nullable
private final MainThreadSupport mainThreadSupport;
// @Nullable
private final Poster mainThreadPoster;
EventBus(EventBusBuilder builder) {
mainThreadSupport = builder.getMainThreadSupport();
// 如果当前线程是主线程 , 才会创建 mainThreadPoster , 否则为空
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
}
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
// 获取该 订阅方法 的线程模式
switch (subscription.subscriberMethod.threadMode) {
case MAIN:
if (isMainThread) {
// 假如在主线程中 , 直接调用
invokeSubscriber(subscription, event);
} else {
// 假如发布线程是子线程 , 则将事件加入队列 , 通过 Handler 切换线程执行
mainThreadPoster.enqueue(subscription, event);
}
break;
}
}
}
二、MainThreadSupport 解析
MainThreadSupport 是一个接口 , 在 AndroidHandlerMainThreadSupport 实现类中的 createPoster
方法中 , 创建了一个 HandlerPoster ;
package org.greenrobot.eventbus;
import android.os.Looper;
/**
* 接口到“主”线程,可以是您喜欢的任何线程。通常在Android上使用Android的主线程。
*/
public interface MainThreadSupport {
boolean isMainThread();
Poster createPoster(EventBus eventBus);
class AndroidHandlerMainThreadSupport implements MainThreadSupport {
private final Looper looper;
public AndroidHandlerMainThreadSupport(Looper looper) {
this.looper = looper;
}
@Override
public boolean isMainThread() {
return looper == Looper.myLooper();
}
@Override
public Poster createPoster(EventBus eventBus) {
return new HandlerPoster(eventBus, looper, 10);
}
}
}
三、MainThreadSupport 解析
调用 mainThreadSupport.createPoster(this)
创建的对象就是 HandlerPoster
对象 , 其本质是一个 Handler
;
调用 void enqueue(Subscription subscription, Object event)
方法 , 将订阅者和订阅方法 , 事件对象 传入该方法 , 将 订阅者 和 事件对象 加入到 PendingPost 链表中 ;
同时调用 sendMessage(obtainMessage())
方法 , 向 Handler 发送消息 , 执行 handleMessage 方法中的业务逻辑 ;
在 handleMessage
方法中 , PendingPost pendingPost = queue.poll()
取出链表元素 , 每个元素中封装了 订阅者 和 事件对象 , eventBus.invokeSubscriber(pendingPost);
通过反射执行订阅方法 ;
HandlerPoster 源码 :
public class HandlerPoster extends Handler implements Poster {
private final PendingPostQueue queue;
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
private boolean handlerActive;
protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
super(looper);
this.eventBus = eventBus;
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
queue = new PendingPostQueue();
}
// 将订阅者和订阅方法 , 事件对象 传入该方法
public void enqueue(Subscription subscription, Object event) {
// PendingPost 是一个链表数据结构 , 将所有的 事件对象 , 订阅者 都封装在了该链表中 ;
// 将 订阅者 和 事件对象 加入到 PendingPost 链表中
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!handlerActive) {
handlerActive = true;
// 向 Handler 发送消息 , 执行 handleMessage 方法
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
}
}
}
// 不断取出 PendingPost 链表中的数据 , 执行订阅方法
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
// 取出链表元素 , 每个元素中封装了 订阅者 和 事件对象
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
// 通过反射执行订阅方法
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
}
四、PendingPost 链表
PendingPost 是一个链表数据结构 , 将所有的 事件对象 , 订阅者 都封装在了该链表中 ;
final class PendingPost {
private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();
Object event;
Subscription subscription;
PendingPost next;
}
相关文章
- 顶级黑客欢乐解析:宝宝事件中人肉搜索的七种方法
- [转]addEventListener() 方法,事件监听
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇
- 【Tokio】监听停止事件
- js点击按钮触发事件的方法(含函数的写法)
- 从源码和日志文件结构中分析 Kafka 重启失败事件
- 《JS原理、方法与实践》- DOM事件
- js中onkeydown回车触发事件的几种方法
- 事件监听
- jQuery常用事件方法详解
- 第15.17节 PyQt(Python+Qt)入门学习:PyQt图形界面应用程序的事件捕获方法大全及对比分析
- PyQt(Python+Qt)实现的GUI图形界面应用程序的事件捕获方法大全及对比分析
- 让BottomSheetDialogFragment透传点击事件
- 概率论与数理统计(一)—— 随机事件与概率
- 【EventBus】事件通信框架 ( 发送事件 | 根据事件类型获取订阅者 | 调用订阅方法 )
- 【EventBus】事件通信框架 ( 订阅方法注册 | 检查订阅方法缓存 | 反射获取订阅类中的订阅方法 )
- 【EventBus】事件通信框架 ( 实现几个关键的封装类 | 消息中心 | 订阅注解 | 订阅方法封装 | 订阅对象-方法封装 | 线程模式 )
- 【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 获取要注入事件的 View 对象 | 通过反射获取 View 组件的事件设置方法 )
- Windows/Linux用户态监控进程启动事件方法
- javascript事件监听与事件委托
- js中事件绑定要注意的事项之如何在方法中自己打印自己的值
- JQuery实现click事件绑定与触发方法分析
- cocos2d ccLayer响应触摸事件方法:CCStandardTouchDelegate 与 CCTargetedTouchDelegate
- [IOS]触摸事件和手势