EventBus分析--事件分发
来源:互联网 发布:linux启动mysql服务 编辑:程序博客网 时间:2024/06/08 08:06
2 事件分发
事件分发一般调用post方法,调用流程图如下,
post方法如下,
public void post(Object event) { //获取当前线程的postingState PostingThreadState postingState = currentPostingThreadState.get(); //取得当前线程的事件队列 List<Object> eventQueue = postingState.eventQueue; //将该事件添加到当前的事件队列中等待分发 eventQueue.add(event); // 判断是否有事件正在分发 if (!postingState.isPosting) { //判断是否是在主线程post 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; } } }
currentPostingThreadState的定义如下,
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() { @Override protected PostingThreadState initialValue() { return new PostingThreadState(); } };
ThreadLocal 是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,而这段数据是不会与其他线程共享的。
currentPostingThreadState实际是一个包含了PostingThreadState的ThreadLocal对象,这样可以保证取到的都是自己线程
对应的数据。
PostingThreadState是Event的内部类,主要包含一些变量,
final static class PostingThreadState { final List<Object> eventQueue = new ArrayList<Object>(); //当前线程的事件队列 boolean isPosting; //是否有事件正在分发 boolean isMainThread; //post的线程是否是主线程 Subscription subscription; //订阅者 Object event; //订阅事件 boolean canceled; //是否取消}
PostingThreadState中包含了当前线程的事件队列,就是当前线程所有分发的事件都保存在eventQueue事件队列中。
以及订阅者订阅事件等信息,有了这些信息就可以从事件队列中取出事件分发给对应的订阅者。
postSingleEvent方法如下,
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error { Class<?> eventClass = event.getClass();//得到事件类型 boolean subscriptionFound = false; if (eventInheritance) { //是否触发订阅了该事件(eventClass)的父类,以及接口的类的响应方法. 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)); } } }
lookupAllEventTypes方法会将事件放入eventTypesCache变量中保存,
private static List<Class<?>> lookupAllEventTypes(Class<?> eventClass) { synchronized (eventTypesCache) { List<Class<?>> eventTypes = eventTypesCache.get(eventClass); if (eventTypes == null) { eventTypes = new ArrayList<>(); Class<?> clazz = eventClass; while (clazz != null) { eventTypes.add(clazz); addInterfaces(eventTypes, clazz.getInterfaces()); clazz = clazz.getSuperclass(); } eventTypesCache.put(eventClass, eventTypes); } return eventTypes; } }
该变量的定义如下,
private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();
放入eventTypesCache中统一管理,避免不必要的资源浪费。
postSingleEventForEventType方法首先根据根据事件类型获取所有的订阅者,然后向每个订阅者分发事件,
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);•••
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { case POSTING://默认的 ThreadMode,表示在执行 Post 操作的线程直接调用订阅者的事件响应方法, //不论该线程是否为主线程(UI 线程)。 invokeSubscriber(subscription, event); break; case MAIN: //在主线程中执行响应方法。 if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; case BACKGROUND: //在后台线程中执行响应方法。 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); } }
invokeSubscriber方法如下,
void invokeSubscriber(Subscription subscription, Object event) { try { subscription.subscriberMethod.method.invoke(subscription.subscriber, event); } catch (InvocationTargetException e) { handleSubscriberException(subscription, event, e.getCause()); } catch (IllegalAccessException e) { throw new IllegalStateException("Unexpected exception", e); } }
通过反射调用订阅者的订阅函数 并把event作为参数传入。
小结:
1、首先获取当前线程的PostingThreadState对象从而获取到当前线程的事件队列
2、通过事件类型获取到所有订阅者集合
3、通过反射执行订阅者中的订阅方法
阅读全文
0 0
- EventBus分析--事件分发
- EventBus事件分发
- EventBus事件分发框架解读
- EventBus事件总线分发库
- Eventbus是如何实现事件分发的
- 事件总线分发库EventBus的使用
- 事件分发处理EventBus的使用
- 事件总线分发库EventBus详解
- Android_RxJava代替EventBus实现事件分发
- 事件总线分发库--EventBus的使用
- EventBus分析--事件的注册
- 事件总线分发库EventBus框架的简单使用
- 如何用RxJava替代EventBus进行事件的分发?
- Android事件分发分析(一)
- Android事件分发深入分析
- View事件分发源码分析
- View事件分发机制分析
- Android事件分发源码分析
- MAPREDUCE框架结构及核心运行机制
- Ubuntu 知识点存储
- 字符编码 与 解码
- int swap
- Set,List,Map的区别
- EventBus分析--事件分发
- 进程间通信(四)--Peterson算法
- 【FastDFS专题】fastdfs使用实战(概念篇)
- php个人备忘笔记
- C#之MS SQL SERVER
- Android Studio JNI开发入门教程
- window.scrollY和scrollX在IE下报错的解决方法
- C++
- 学习之旅2