EventBus源码学习

前言

之前使用EventBus不多,所以也没有比较好的去学习它,后来使用得比较频繁,而且感觉很好用,所以对它的使用进一步学习外,最近还对它的实现进行学习。

EventBus的创建

EventBus采用单例和Builder模式对本身进行创建:

public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}
public EventBus() {
    this(DEFAULT_BUILDER);
}

EventBus(EventBusBuilder builder) {
    //事件类型<——>Subscription集合(封装类注册者与注册者里边@Subscribe标注的方法)
    subscriptionsByEventType = new HashMap<>();
    //注册者<——>事件类型的集合(注册者里边所关注的事件类型)
    typesBySubscriber = new HashMap<>();
    //存放粘性事件的集合
    stickyEvents = new ConcurrentHashMap<>();
    //是否发送事件后观察该事件的父类的观察者也会收到该事件
    eventInheritance = builder.eventInheritance;
    //......
}

注册

public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//1
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);//2
        }
    }
}

1:通过subscriberMethodFinder对象去获取注册者中所有被@Subscribe注解的方法

2:进一步将注册者与事件接收方法绑定

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    Class<?> eventType = subscriberMethod.eventType;
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);//1
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(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);
        }
    }
//2
    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;
        }
    }
//3
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);
//4
    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);
        }
    }
}

1:将注册者与接收事件方法封装成Subscription,然后通过事件类型去获取对应的Subscription列表,将事件类型与Subscription列表对应起来,它们的关系为事件类型一对方法多;已经注册过的则不能再注册,否则会抛出异常。

2:通过事件接收的优先级来放入新的Subscription到列表中

3:收集该注册者中关注的事件类型到事件类型集合中,对应关系为注册者一对事件类型多

4:如果该注册方法可接收粘性事件,则直接进行对该方法的执行

以上的流程便把注册者(subscriber)、事件类型(eventType)和Subscription(将注册者与注册方法封装起来)的关系对应了起来,完成了注册的请求

事件的发送

public void post(Object event) {
    //1
    PostingThreadState postingState = currentPostingThreadState.get();
    List<Object> eventQueue = postingState.eventQueue;
    eventQueue.add(event);

    if (!postingState.isPosting) {
        postingState.isMainThread = isMainThread();
        postingState.isPosting = true;
        if (postingState.canceled) {
            throw new EventBusException("Internal error. Abort state was not reset");
        }
        try {
            //2
            while (!eventQueue.isEmpty()) {
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
            //3
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}

1:通过currentPostingThreadState获取当前线程的PostingThreadState,然后将事件添加到当前线程事件队列中,更滑一些当前操作的状态,比如当前是否为主线程、正在发送事件等状态

2:逐个发送当前队列的事件

3:重置当前状态

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;
    if (eventInheritance) {//1
        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 {//2
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
    }
    if (!subscriptionFound) {
        if (logNoSubscriberMessages) {
            logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
        }
        if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                eventClass != SubscriberExceptionEvent.class) {//3
            post(new NoSubscriberEvent(this, event));
        }
    }
}

1:如果eventInheritance为true,则会进一步搜索当前事件类型的所以父类,然后逐个通知注册观察了该事件和该事件的父类的方法

2:如果eventInheritance为false,则直接注册观察了事件的方法

3:如果没有找到观察该事件的方法,则会发送出一个NoSubscriberEvent的事件

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) {
          //...
                postToSubscription(subscription, event, postingState.isMainThread);
                aborted = postingState.canceled;
          //...
        return true;
    }
    return false;
}

postSingleEventForEventType方法中,会根据事件类型获取对应的subscriptions,然后逐个遍历执行进一步操作调用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 MAIN_ORDERED:
            if (mainThreadPoster != null) {
                mainThreadPoster.enqueue(subscription, event);
            } else {
                // temporary: technically not correct as poster not decoupled from subscriber
                invokeSubscriber(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);
    }
}

postToSubscription方法会根据subscription封装的subscriberMethod去获取该方法指定在哪种线程中执行,然后再对应的线程中最后都会执行invokeSubscriber(subscription, event)方法。

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);
    }
}

invokeSubscriber方法里边通过反射操作,执行了注册对象中相应的方法并把事件对象传递进去。

总结

到此EventBus的创建、事件发送和事件消费的流程算是走了一遍,当然它还有很多的实现细节和其他方面的知识,比如线程模型等。总体而言感觉EventBus的源码学习起来没有其他的费劲,希望本分享能够带给你学习它的帮助。

你可能感兴趣的:(Android)