EvenBus源码分析

源码分析

EventBus 是一款在 Android 开发中使用的发布/订阅事件总线框架,基于观察者模式,将事件的接收者和发送者分开,简化了组件之间的通信,使用简单、效率高、体积小!

分析它的源码,我们先从获取实例入手,然后分析下它的register方法,unregister方法和post方法的实现细节。

1、获取实例

一般我们都是通过getDefault方法直接获取到EventBus的默认实例,getDefault方法内部是用了一个默认的EventBusBuilder(DEFAULT_BUILDER)来创建EventBus,当然,我们也可以通过EventBus的builder()方法获取到EventBusBuilder实例,从而来构建符合我们自己需求的EventBus实例。

// 默认的EventBusBuilder
private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

// 静态单例
static volatile EventBus defaultInstance;

public static EventBus getDefault() {
     EventBus instance = defaultInstance;
        // 单例模式获取实例
        ...
         instance = EventBus.defaultInstance = new EventBus();
     }
     return instance;
 }

 // 获取EventBusBuilder实例
 public static EventBusBuilder builder() {
     return new EventBusBuilder();
 }

 // 默认构造,使用默认的EventBusBuilder
 public EventBus() {
     this(DEFAULT_BUILDER);
 }

 // 调用该构造创建实例
 EventBus(EventBusBuilder builder) {
     logger = builder.getLogger();
     ...
 }

2、注册(register)

public void register(Object subscriber) {
    // 获取订阅类(注册类)的class对象
    Class<?> subscriberClass = subscriber.getClass();

    // 找到该类中所有的订阅了事件的方法(以下称订阅方法)集合(即使用@Subscribe注解修饰的方法)
    // SubscriberMethod内部包含订阅方法的信息(线程模式、优先级、事件类型、是否是粘性事件等)
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);

    synchronized (this) {
        // 遍历订阅方法集合,以完成订阅
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            // 传入订阅类和订阅方法
            subscribe(subscriber, subscriberMethod);
        }
    }
}

register方法的大概流程是通过订阅类对象找到该类中所有被@Subscribe注解修饰的方法,然后通过subscribe方法完成方法的订阅,接下来看下findSubscriberMethods内部的实现:


// 查询订阅类中所有的订阅方法,返回订阅方法集合
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {

    // METHOD_CACHE是个ConcurrentHashMap,线程安全
    // 查找METHOD_CACHE中是否已存在订阅类的订阅方法的集合
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);

    // 如果有,则直接返回,避免重复查找
    if (subscriberMethods != null) {
        return subscriberMethods;
    }

    // ignoreGeneratedIndex是否忽略注解生成器,默认为false
    if (ignoreGeneratedIndex) {
        subscriberMethods = findUsingReflection(subscriberClass);
    } else {
        // 通过反射查找订阅方法
        subscriberMethods = findUsingInfo(subscriberClass);
    }

    // 如果在订阅类中没有找到订阅方法,则抛出异常
    if (subscriberMethods.isEmpty()) {
        throw new EventBusException("Subscriber " + subscriberClass
                + " and its super classes have no public methods with the @Subscribe annotation");
    } else {
        // 将订阅类作为key,订阅方法的集合作为value存入Map
        METHOD_CACHE.put(subscriberClass, subscriberMethods);
        return subscriberMethods;
    }
}

// 默认是调用了findUsingInfo方法
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    // 获取FindState(相当于一个辅助类),从FIND_STATE_POOL池中取,如果没有则创建个实例
    FindState findState = prepareFindState();
    // 将订阅类的引用存入FindState
    findState.initForSubscriber(subscriberClass);

    // 循环直到findState的clazz为空(clazz为java.或android.或javax.等系统类则结束查找)
    while (findState.clazz != null) {
        // 由于subscriberInfoIndexes()为空,则该方法就返回null
        // subscriberInfoIndexes(注解处理器生成的索引类),通过EventBus.builder().addIndex(索引类).build()添加进来,这个索引类后面再单独分析下
        findState.subscriberInfo = getSubscriberInfo(findState);
        if (findState.subscriberInfo != null) {
            SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
            for (SubscriberMethod subscriberMethod : array) {
                if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                    findState.subscriberMethods.add(subscriberMethod);
                }
            }
        } else {
            // 最终调用这个方法
            findUsingReflectionInSingleClass(findState);
        }

        // 将clazz指向订阅类的父类,直到找到java.或android.或javax.等系统类,则返回null
        findState.moveToSuperclass();
    }
    // 获取订阅方法集合并释放FindState
    return getMethodsAndRelease(findState);
}

// 通过反射获取类的订阅方法
private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
        // This is faster than getMethods, especially when subscribers are fat classes like Activities
        // 使用getDeclaredMethods相对于getMethods效率高点,因为只获取当前类的所有方法,而getMethods还会获取父类中的方法
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
        // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149
        // 在部分手机使用getDeclaredMethods会报NoClassDefFoundError异常,所以抛异常的话就使用getMethods获取类的所有方法
        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);
                // 判断是否存在Subscribe注解
                if (subscribeAnnotation != null) {
                    Class<?> eventType = parameterTypes[0]; // 获取事件类型
                    // 判断findState的map中是否存在该添加过该事件类型为key的数据
                    if (findState.checkAdd(method, eventType)) {
                        // 获取注解上的线程模式,默认是POSTING,即在当前运行的线程
                        ThreadMode threadMode = subscribeAnnotation.threadMode();
                        // 构造SubscriberMethod,存入findState的订阅方法集合中
                        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");
        }
    }
}

到这里,我们就获取到了该订阅类中的所有订阅方法,那我们回到register方法,遍历了所有的订阅方法,然后调用了subscribe方法:


private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    // 获取订阅方法中的事件类型
    Class<?> eventType = subscriberMethod.eventType;

    // 构造Subscription,包含订阅者和订阅方法信息(以下称订阅信息对象)
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);

    // 通过事件类型获取使用该事件类型的订阅信息对象的集合,subscriptionsByEventType是一个key为事件类型,value为该事件类型对应的订阅信息对象的集合
    // 这里划重点,后面post方法就通过这个map来获取所有使用了该事件类型的订阅信息对象,从而通过invoke对应的方法
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);

    // 没有找到事件类型对应的订阅信息对象的List
    if (subscriptions == null) {
        subscriptions = new CopyOnWriteArrayList<>(); // 新建
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {

        // 事件类型对应的订阅信息对象集合中已包含了该Subscription对象,则抛出异常
        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++) {
        // 根据优先级插入新构造的Subscription(订阅信息对象)
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }

    // typesBySubscriber是一个key为订阅者,value为该订阅者中的所有事件类型组成的集合,作用是在反注册时移除该订阅者的订阅方法
    // 通过订阅者,获取其内部的所有的事件类型的集合
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    // 将事件类型添加到集合中
    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<Class>).
            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);
        }
    }
}

这里subscribe方法主要是配置了两个map的数据,subscriptionsByEventType和typesBySubscriber,还有粘性事件的处理,subscriptionsByEventType存储了事件类型与其对应的订阅信息对象集合的映射,用于通过事件类型去找到所有的订阅方法,从而进行方法的调用,typesBySubscriber存储了订阅类与其所有事件类型的映射,用于反注册中解除订阅关系。

3、反注册(unregister)


// 反注册
public synchronized void unregister(Object subscriber) {
    // 获取该订阅者中的所有事件类型的集合
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        // 遍历事件类型的集合
        for (Class<?> eventType : subscribedTypes) {
            // 通过事件类型找到对应的订阅者,将该数据从subscriptionsByEventType中移出
            unsubscribeByEventType(subscriber, eventType);
        }
        // 将该订阅者移出Map
        typesBySubscriber.remove(subscriber);
    } else {
        logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}

private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
    // 通过事件类型,获取所有使用了该事件类型的订阅方法的集合
    List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    if (subscriptions != null) {
        int size = subscriptions.size();
        // 遍历订阅信息对象集合
        for (int i = 0; i < size; i++) {
            Subscription subscription = subscriptions.get(i);
            // 找到该事件类型的订阅者,移出Map
            if (subscription.subscriber == subscriber) {
                subscription.active = false;
                subscriptions.remove(i);
                i--;
                size--;
            }
        }
    }
}


反注册主要的处理就是将该订阅类的所有订阅信息从对应的Map中移出。

4、发送事件(post)


private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
    @Override
    protected PostingThreadState initialValue() {
        return new PostingThreadState();
    }
};

// 发送事件方法
public void post(Object event) {
    // currentPostingThreadState是个存储PostingThreadState的ThreadLocal
    // PostingThreadState包含事件队列、当前是否是主线程等信息
    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 {
            // 循环发送事件
            while (!eventQueue.isEmpty()) {
                postSingleEvent(eventQueue.remove(0), postingState);
            }
        } finally {
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    Class<?> eventClass = event.getClass(); // 获取当前事件类型
    boolean subscriptionFound = false; // 是否找到对应的订阅信息对象

    // eventInheritance标识是否需要查找该事件的父类
    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 {
        // 通过事件类型查找是否有对应的订阅信息对象,如果有,则调用方法,并返回true
        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) {
            post(new NoSubscriberEvent(this, event));
        }
    }
}

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赋值对应的事件和subscription
            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;
}

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 {
                // 利用Handler发送到主线程执行,最终也是执行invokeSubscriber方法
                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) {
                // 实现Runnable,最终通过EventBus的ExecutorService(线程池)执行
                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);
    }
}

// 最终调用的唤醒订阅类中的订阅方法
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这个Map来实现,注册的时候往里面存入订阅信息对象数据,而当发送事件时,从这个Map中查询到对应事件的订阅信息对象,然后通过不同的线程模式去触发对应的方法。typesBySubscriber这个Map存储了订阅类中的所有订阅事件类型,从而可以在反注册时,查询到对应的订阅类数据,然后将它从subscriptionsByEventType中移出。粘性事件和注解处理器生成的索引类放到后面再分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值