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、通过反射执行订阅者中的订阅方法

原创粉丝点击