EventBus源码解析一

    xiaoxiao2025-11-09  9

    在这一篇文章中,我们会介绍在调用 EventBus.getDefault().register(this); 之后都发生了什么 首先介绍一下各种名词的含义:

    subscriber 类的成员函数有用 @Subscribe() 注解修饰的都能称为subscriber(订阅者)Subscription 封装subscriber和subscriberMethod的实体类 然后介绍一下EventBus中比较关键的几个Map类型的属性: private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;//Key为Event(事件实体),Value为封装好的Subscription(订阅者)集合 private final Map<Object, List<Class<?>>> typesBySubscriber;//Key为Subscriber(订阅者),Value为订阅者感兴趣的Event(事件)集合 private final Map<Class<?>, Object> stickyEvents;//置顶事件集合,Key为Event实体类,Value为具体Event对象

    register过程

    //EventBus.class /** * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they * are no longer interested in receiving events. * * Subscribers have event handling methods that must be annotated by {@link Subscribe}. * The {@link Subscribe} annotation also allows configuration like {@link * ThreadMode} and priority. */ public void register(Object subscriber) { Class subscriberClass = subscriber.getClass(); List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }

    调用register()方法需要传入订阅者;这个订阅者可以为调用者本身,也可以为其他订阅者 在 register() 方法内部会调用 SubscriberMethodFinder.findSubscriberMethods(Class subscriberClass) 方法来获取订阅者内部可以接收订阅事件的方法,方法实现如下:

    //SubscriberMethodFinder.class List findSubscriberMethods(Class subscriberClass) { List subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } 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 { METHOD_CACHE.put(subscriberClass, subscriberMethods); return subscriberMethods; } }

    注意到作者使用了缓存机制METHOD_CACHE,变量声明如下:private static final Map, List> METHOD_CACHE = new ConcurrentHashMap<>();可见作者还考虑了多线程的情况,使用这个缓存机制可以减少重复获取订阅者处理事件的方法,提高运行效率 关于ignoreGeneratedIndex就不得不提一下在 EventBus高级使用姿势 中提到的EventBus 3.X新特性Subscriber Index,如果看过上篇文章,那么理解这个变量的含义就不困难了,ignoreGeneratedIndex的默认值为false,也就是默认采用生成的index获取订阅者的方法。 这里我们首先分析 findUsingReflection(Class subscriberClass) 方法,看名字就能猜出来是采用反射方法获取订阅者方法,具体实现上源码:

    private List findUsingReflection(Class subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findUsingReflectionInSingleClass(findState); findState.moveToSuperclass(); } return getMethodsAndRelease(findState); }

    很简短的一段代码,在代码中我们遇到了新的朋友FindState,这个类是SubscriberMethodFinder的内部类,具体内容后面再讲,注意关键代码是while循环,首先是用反射方法获取订阅者方法,然后转移至父类,获取父类事件处理函数,一直到java或Android提供的系统类,完成对订阅者方法的遍历,找出所有的订阅方法 现在看一下FindState类中的属性

    final List subscriberMethods = new ArrayList<>(); final Map anyMethodByEventType = new HashMap<>(); final Map subscriberClassByMethodKey = new HashMap<>(); final StringBuilder methodKeyBuilder = new StringBuilder(128); Class subscriberClass; Class clazz; boolean skipSuperClasses; SubscriberInfo subscriberInfo;

    这里主要说明一下subscriberClass和clazz,其他见名思意(作者这点做的很不错),subscriberClass代表的是订阅者本身,也就是register函数的参数,自始至终不会变;clazz会在遍历方法过程中变化,比如目前在遍历父类方法,clazz变量就指向父类 回到findSubscriberMethods()函数,除了findUsingReflection()方法还有findUsingInfo()方法,现在我们分析一下findUsingInfo()方法,先上函数实现:

    private List findUsingInfo(Class subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { 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); } findState.moveToSuperclass(); } return getMethodsAndRelease(findState); }

    这里使用了FindState中的属性SubscriberInfo,注意这是一个接口,具体实现在Subscriber Index过程中实现的,第一次调用getSubscriberInfo()方法会从build过程中生成的index中取得subscriberInfo,然后每调用一次getSubscriberInfo()方法都会去的父类的subscriberInfo,这点需要注意一下,感兴趣的可以看subscriberInfo()代码,可以发现如果subscriberInfo为空的话,会采用反射方法获取订阅者方法,这和我们前一篇文章中介绍的特性一致 这里需要特别说明一下findState设计的巧妙之处:在SubscriberMethodFinder内部有一个属性FIND_STATE_POOL,这是一个大小为4的FindState数组:

    在prepareFindState()阶段,会从FIND_STATE_POOL中取出不为空的FindState对象,然后将对应位置置空,返回FindState对象,这样可以避免多线程读写冲突以及读写不一致情况发生在getMethodsAndRelease()阶段,会遍历FIND_STATE_POOL,找到为空的位置将使用完的FindState对象放进去,可以在下一次的prepareFindState()阶段复用,这样可以减少实例化对象所产生的额外消耗

    回到register()方法中,既然我们拿到了订阅者内部的订阅函数,下一步应该是注册这些函数到EventBus中,别慌,我们可以发现会对得到的subscriberMethods列表循环调用subscribe()方法,那么这个方法具体是做什么的呢,我猜应该是订阅函数,嗯看名字就知道,下面我们来分析分析:

    // Must be called in synchronized block private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class eventType = subscriberMethod.eventType; Subscription newSubscription = new Subscription(subscriber, subscriberMethod); CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(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; } } List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); //置顶事件,在注册EventBus的时候就会发送事件到订阅者的时间处理函数中 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<Map.Entry<Class<?>, Object>> = 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); } } }

    首先是根据事件类型取得同类型事件的订阅者集合,然后根据事件处理方法的优先级确定插入位置,然后根据订阅者类型插入订阅者事件集合,最后就是处理置顶之间,在源码中可以发现:置顶事件的发送是在注册EventBus阶段

    至此,注册EventBus过程分析完了,如有不对的地方,欢迎在评论中指正

    转载请注明原文地址: https://ju.6miu.com/read-1303998.html
    最新回复(0)