EventBus分析--事件分发

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值