美文网首页
EventBus 源码解读

EventBus 源码解读

作者: peterXpq | 来源:发表于2020-12-01 14:55 被阅读0次

1、获取单例实例:

public static EventBus getDefault() {
    // 叨叨两句,双重锁机制 才是 单例创建的最佳姿势
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

2、调用 注册方法

public void register(Object subscriber) {
    //获取订阅的当前类
    Class<?> subscriberClass = subscriber.getClass();
    //获取到当前订阅类中被@Subscribe 注解的方法
    // 先会从缓存中获取,此处省略
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}
//  订阅的时候会加入到 
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    // 事件类型
    Class<?> eventType = subscriberMethod.eventType;
    // 创建新的订阅对象,用Subscription类包装订阅者以及订阅方法
    Subscription newSubscription = new Subscription(subscriber,subscriberMethod);
    // 取出所有订阅了该事件的Subscription集合
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    // 可能此eventType是第一次出现,初始化一下
  if (subscriptions == null) {
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
        if (subscriptions.contains(newSubscription)) {
            throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                    + eventType);
        }
    }
    // 优先级重新排序下
    int size = subscriptions.size();
    for (int i = 0; i <= size; i++) {
      //  将新添加注解优先级高的添加到集合中
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }
    // 该订阅者所有的关心的事件类型集合  比如:一个Activity 有多个事件,就会有多个观察的实体Bean
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    // 第一次先初始化
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);
// 如果当前订阅方法接受粘性事件,并且订阅方法关心的事件在粘性事件集合中,那么将该event事件post给subscriber
    if (subscriberMethod.sticky) {
        if (eventInheritance) {
            Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
            for (Map.Entry<Class<?>, Object> entry : entries) {
                Class<?> candidateEventType = entry.getKey();
                if (eventType.isAssignableFrom(candidateEventType)) {
                    Object stickyEvent = entry.getValue();
                    checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                }
            }
        } else {
            Object stickyEvent = stickyEvents.get(eventType);
            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
        }
    }
}

================至此,register 方法完成===========================
3、调用 post 方法:

 public void post(Object event) {
    PostingThreadState postingState = currentPostingThreadState.get();
  // 构建了事件队列
    List<Object> eventQueue = postingState.eventQueue;
  //  每post 一个事件进来,就加入到事件队列中
    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 循环,按照 先进先出原则抽取事件分发
            while (!eventQueue.isEmpty()) {
            // 从 每次remove(0)可以看出每次都是从队列的头抽取对象
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}

post 里面主要做了以下操作:

  • 从ThreadLocal中获取PostingState,然后把事件Event添加到队列中 postingState.eventQueue
    这里 PostingThreadState 类为:
 /** For ThreadLocal, much faster to set (and get multiple values). */
    final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<Object>();
        boolean isPosting;
        boolean isMainThread;
        Subscription subscription;
        Object event;
        boolean canceled;
    }

用来保存一些状态

  • 判断当前时间是否发送,进到 if 中,设置是否是主线程以及 posting = true,然后循环调用队列 postingSingleEvent(eventQueue.remove(0), postingState),使用完的事件则被移除出队列
  • 最后finally 设置属性为false

看下事件处理方法

 private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        //该eventInheritance上面有提到,默认为true,即EventBus会考虑事件的继承树
        //如果事件继承自父类,那么父类也会作为事件被发送
        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);
        }
      // 结果判断,如果没找到订阅该事件的订阅者,发送 NoSubscriberEvent  事件
        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));
            }
        }
    }

Inheritance:遗产,继承

看下调用的 postingSingleEventForEventType 这个方法

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
          // 1、根据事件类型eventType拿到方法集
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                //②保存当前状态到PostingState
                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;
    }

调用postToSubscription来执行事件

 private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                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);
        }
    }

首先获取threadMode,即订阅方法运行的线程,如果是POSTING,那么直接调用invokeSubscriber()方法即可,如果是MAIN,则要判断当前线程是否是MAIN线程,如果是也是直接调用invokeSubscriber()方法,否则会交给mainThreadPoster来处理,其他情况相类似。这里会用到三个Poster,由于粘性事件也会用到这三个Poster,因此我把它放到下面来专门讲述。而EventBus#invokeSubscriber的实现也很简单,主要实现了利用反射的方式来调用订阅方法,这样就实现了事件发送给订阅者,订阅者调用订阅方法这一过程

invokeSubscriber

void invokeSubscriber(Subscription subscription, Object event) {
    try {
        subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
    } 
    //...
}

整个流程图,更加清晰明了


流程图

相关文章

网友评论

      本文标题:EventBus 源码解读

      本文链接:https://www.haomeiwen.com/subject/tjwviktx.html