EventBus源码解析

EventBus的基本用法

注册事件
EventBus.getDefault().register(this);
解除注册
EventBus.getDefault().unregister(this);
发送事件
EventBus.getDefault().post(event);
处理事件
@Subscribe(threadMode = ThreadMode.MAIN)
public void XXX(Object event) {
    ...
}

注解@Subscribe

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;

    /**
     * If true, delivers the most recent sticky event (posted with
     * {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
     */
    boolean sticky() default false;

    /** Subscriber priority to influence the order of event delivery.
     * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
     * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
     * delivery among subscribers with different {@link ThreadMode}s! */
    int priority() default 0;
}

这是一个自定义的运行时注解,有三个属性,threadMode、sticky、priority。
threadMode表示处理事件所在的线程,有POSTING、MAIN、BACKGROUND和ASYNC四种线程模型,默认为POSTING。
sticky是否是粘性事件,默认为false。
priority为优先级,默认值为0,值越大优先级越高。

EventBus的getDefault()

EventBus.getDefault()采用单例模式,创建一个EventBus对象,初始化了subscriptionsByEventType和typesBySubscriber两个HashMap,用以存储订阅者、订阅方法和订阅事件的相关信息。

//这是一个单例模式
public static EventBus getDefault() {
    if (defaultInstance == null) {
        synchronized (EventBus.class) {
            if (defaultInstance == null) {
                //创建了一个EventBus对象
                defaultInstance = new EventBus();
            }
        }
    }
    return defaultInstance;
}

public EventBus() {
    this(DEFAULT_BUILDER);
}

EventBus(EventBusBuilder builder) {
    //一个HashMap,以事件类型eventType为key,以存储了订阅者和订阅方法的集合CopyOnWriteArrayList为value
    subscriptionsByEventType = new HashMap<>();
    //一个HashMap,以订阅者subscriber为key,以订阅者所订阅的事件类型eventType的集合List>为value
    typesBySubscriber = new HashMap<>();
    //粘性事件相关的集合,这里不对粘性事件做分析,有兴趣的自行学习
    stickyEvents = new ConcurrentHashMap<>();
    //主线线程事件发送者
    mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
    //后台线程事件发送者
    backgroundPoster = new BackgroundPoster(this);
    //异步线程事件发送者
    asyncPoster = new AsyncPoster(this);
        ...
}

注册register

public void register(Object subscriber) {
    Class subscriberClass = subscriber.getClass();
    //获取订阅者的订阅方法的集合,后面有对findSubscriberMethods的描述
    List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

// Must be called in synchronized block
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    Class eventType = subscriberMethod.eventType;
    //Subscription封装了订阅者subscriber和订阅方法subscriberMethod
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
    //subscriptions若为空,先初始化,subscriptions已包含newSubscription,说明已被注册过,抛异常
    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++) {
        //按优先级把newSubscription添加到subscriptions,即添加到subscriptionsByEventType
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }

    List> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    //把eventType添加到subscribedEvents,即添加到typesBySubscriber
    subscribedEvents.add(eventType);

    //粘性事件相关处理
    if (subscriberMethod.sticky) {
        if (eventInheritance) {
            // Existing sticky events of all subclasses of eventType have to be considered.
            // Note: Iterating over all events may be inefficient with lots of sticky events,
            // thus data structure should be changed to allow a more efficient lookup
            // (e.g. an additional map storing sub classes of super classes: Class -> List).
            Set, Object>> entries = stickyEvents.entrySet();
            for (Map.Entry, 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);
        }
    }
}

从上面代码可以看出,注册其实就是把当前订阅者相关的所有newSubscription存入subscriptionsByEventType,把当前订阅者订阅的所有eventType存入typesBySubscriber。

因为newSubscription包含了订阅者subscriber和订阅方法subscriberMethod,subscriptionsByEventType的key为事件类型eventType,
所以在subscriptionsByEventType中可以根据事件类型eventType获取所有的类型为eventType的订阅方法subscriberMethod。因为typesBySubscriber的key为订阅者subscriber,所以在typesBySubscriber中可以根据订阅者subscriber获取订阅者订阅的所有的事件类型eventType。

subscriberMethodFinder.findSubscriberMethods(subscriberClass)

方法findSubscriberMethods是为了获取订阅者的订阅方法的集合List,查看findSubscriberMethods这个方法的源码可以发现如果不使用索引,最终会调用findUsingReflectionInSingleClass方法,而默认是不使用索引的,对索引感兴趣的请自行学习,下面是findUsingReflectionInSingleClass方法的源码:

private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
        // This is faster than getMethods, especially when subscribers are fat classes like Activities
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
        //获取订阅者的所有方法
        // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
        methods = findState.clazz.getMethods();
        findState.skipSuperClasses = true;
    }
    for (Method method : methods) {
        int modifiers = method.getModifiers();
        //方法名前有public,没有abstract、static
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
            Class[] parameterTypes = method.getParameterTypes();
            //方法只有一个参数
            if (parameterTypes.length == 1) {
                //方法的@Subscribe注解
                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                if (subscribeAnnotation != null) {
                    Class eventType = parameterTypes[0];
                    if (findState.checkAdd(method, eventType)) {
                        //获取注解中的threadMode
                        ThreadMode threadMode = subscribeAnnotation.threadMode();
                        //findState.subscriberMethods是一个List集合,创建订阅方法SubscriberMethod添加到集合中
                        findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                    }
                }
            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException("@Subscribe method " + methodName +
                        "must have exactly 1 parameter but has " + parameterTypes.length);
            }
        } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
            String methodName = method.getDeclaringClass().getName() + "." + method.getName();
            throw new EventBusException(methodName +
                    " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
        }
    }
}

从上面源码中可以看出,集合findState.subscriberMethods就是我们要获取的集合,最后通过getMethodsAndRelease(FindState findState)从FindState中获取这个集合

解除注册unregister

/** Unregisters the given subscriber from all event classes. */
public synchronized void unregister(Object subscriber) {
    //根据订阅者subscriber获取订阅者订阅的所有的事件类型
    List> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        for (Class eventType : subscribedTypes) {
            //从subscriptionsByEventType中移除订阅者对应的subscription
            unsubscribeByEventType(subscriber, eventType);
        }
        //移除订阅者订阅的所有的事件类型
        typesBySubscriber.remove(subscriber);
    } else {
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}

/*
*从subscriptionsByEventType中移除订阅者对应的subscription,subscription包含subscriberMethod,
*所以其实是从subscriptionsByEventType中移除订阅者对应的处理eventType类型事件的方法subscriberMethod
*/
/** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
private void unsubscribeByEventType(Object subscriber, Class eventType) {
    //获取所有的类型为eventType的Subscription的集合
    List subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions != null) {
        int size = subscriptions.size();
        for (int i = 0; i < size; i++) {
            Subscription subscription = subscriptions.get(i);
            //判断是否是当前订阅者subscriber
            if (subscription.subscriber == subscriber) {
                subscription.active = false;
                subscriptions.remove(i);
                i--;
                size--;
            }
        }
    }
}

从上面代码可以看出,解除注册其实就是从typesBySubscriber中移除订阅者订阅的所有的事件类型eventType,从subscriptionsByEventType中移除所有当前订阅者对应的处理eventType类型事件的方法subscriberMethod。

发送事件post

post方法最终调用的是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);
    }
}

从上面可以看出发送者和处理函数在相同线程直接调用invokeSubscriber,不相同时,分别调用mainThreadPoster.enqueue、backgroundPoster.enqueue和asyncPoster.enqueue。其中mainThreadPoster.enqueue是通过Handler将消息发送到主线程最终再调用invokeSubscriber,而backgroundPoster.enqueue和asyncPoster.enqueue都是通过调用线程池的线程的run方法最终调用invokeSubscriber,所以postToSubscription方法最终调的都是invokeSubscriber方法,只是所在线程不同罢了。

从invokeSubscriber的源码可以看出,它通过反射调用处理事件的方法,方法的参数是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);
    }
}

最后

EventBus维护了subscriptionsByEventType和typesBySubscriber两个HashMap,其中typesBySubscriber的key为订阅者subscriber,value为订阅者订阅的所有的事件类型eventType的集合,便于注册和解除注册时添加移除当前订阅者订阅的事件类型。subscriptionsByEventType的key为eventType,value为由订阅者和处理eventType类型事件的方法subscriberMethod组成的subscription对象的集合,便于发送事件时通过事件类型eventType获取处理对应事件的方法,最后通过反射机制调用该方法。


欢迎关注.jpg

你可能感兴趣的:(EventBus源码解析)