zoukankan      html  css  js  c++  java
  • 由浅入深了解EventBus:(四)

    事件注册

        在EventBus3.0框架中订阅者对事件进行注册/订阅是通过EventBus类中的register方法来实现的,register的方法参数就是我们的订阅者的实例; 

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

    findSubscriberMethods 

      在register方法中首先获取订阅者的实例的类型,然后通过subscriberMethodFinder类中的findSubscriberMethods方法来查找这个订阅者类型中的所有的消息事件的处理方法列表;获取到所有的消息处理方法后遍历进行订阅/注册;在subscribe方法的内部就是对EventBus类中的Map表进行赋值;

        List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
            List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
            if (subscriberMethods != null) {
                return subscriberMethods;
            }
            //是否忽略注解器生成的MyEventBusIndex类
            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;
            }
        }
    

      subscriberMethodFinder类中的findSubscriberMethods方法中首先是通过从缓存中获取相应的消息事件处理列表;由于EventBus框架采用的是反射机制来处理,性能上肯定没有直接去new对象的效率高,为了解决了这个造成的性能问题,EventBus框架采用编译期间进行对标注了“@Subscribe”注解的函数进行缓存;

       在3.0版本中,EventBus提供了一个EventBusAnnotationProcessor注解处理器来在编译期通过读取@Subscribe()注解并解析,处理其中所包含的信息,然后生成java类来保存所有订阅者关于订阅的信息,这样就比在运行时使用反射来获得这些订阅者的信息速度要快;对于缓存这块以后单独一个章节会讲到,这里不在做深入的分析;

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

     在findUsingReflection 方法中查找SubscriberMethod集合时,使用了FindState来传递消息; 在subscriberMethodFinder类中维护着一个数组长度默认值为4的静态数组,这个数组存储的就是FindState,这边保证了FindState类可以复用,避免重复创造过的FindState对象;

       static class FindState {
            final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
            final Map<Class, Object> anyMethodByEventType = new HashMap<>();
            final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
            final StringBuilder methodKeyBuilder = new StringBuilder(128);
    
            Class<?> subscriberClass;
            Class<?> clazz;
            boolean skipSuperClasses;
            SubscriberInfo subscriberInfo;
    
            void initForSubscriber(Class<?> subscriberClass) {
                this.subscriberClass = clazz = subscriberClass;
                skipSuperClasses = false;
                subscriberInfo = null;
            }
    }

      在FindState类中维护着2个类型字段;subscriberClass类型是订阅者的类型,clazz类型在初始化的时候和subscriberClass类型是一样,当skipSuperClasses为false时,循环查找基类时,clazz类型会重新赋值为订阅者基类的类型;

      当FindState类初始化构造完成后,EventBus3.0框架就开始循环查找订阅者以及基类中的监听事件处理函数;关于查找的具体实现就在findUsingReflectionInSingleClass方法中;

        private void findUsingReflectionInSingleClass(FindState findState) {
            Method[] methods;
            try {
                methods = findState.clazz.getDeclaredMethods();
            } catch (Throwable th) {
                methods = findState.clazz.getMethods();
                findState.skipSuperClasses = true;
            }
            for (Method method : methods) {
                int modifiers = method.getModifiers();
                if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    if (parameterTypes.length == 1) {
                        Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                        if (subscribeAnnotation != null) {
                            Class<?> eventType = parameterTypes[0];
                            if (findState.checkAdd(method, eventType)) {
                                ThreadMode threadMode = subscribeAnnotation.threadMode();
                                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");
                }
            }
        }
    

       在方法的内部,首先通过反射中的getDeclaredMethods方法获取订阅者(或者是基类)中的所有方法;进而循环去校验方法是否是监听事件的处理函数;

       从(modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0 可以看出,事件监听处理函数必须是public;事件监听处理函数中参数必须只有一个,这个从parameterTypes.length == 1就可以看出;最重要的是事件监听处理函数必须是“Subscribe”注解标注的;

       当上述条件都满足的情况,EventBus3.0框架就认为这个函数就是事件监听处理函数,进而创建SubscriberMethod类,并将其添加到FindState类中的subscriberMethods 集合中;再此操作之前,FindState类会通过checkAdd方法来校验是否已经添加过此事件类型;

       FindState类中的moveToSuperclass方法作用就是判断是否支持从父类查找,当FindState类中skipSuperClasses为true时,直接跳出循环,当skipSuperClasses为false时,将FindState类中calzz字段赋值为基类的类型,然后继续while循环查找,直到calzz类为系统的类型时,跳出循环;

       当所有的循环查找结束后,执行getMethodsAndRelease方法,其实就是将 FindState类中的subscriberMethods字段返回,并且重置subscriberMethodFinder类中的FindState数组;

     subscribe

         当通过subscriberMethodFinder类获取到订阅者中所有的事件监听函数时,下一步就是方法的订阅;在subscribe方法中接收2个参数,一个是订阅者的实例,另外一个是订阅者中的监听事件处理函数的封装的SubscriberMethod类;

      private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
            Class<?> eventType = subscriberMethod.eventType;
            Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
            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);
                }
            }
    
            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);
    
            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);
                }
            }
        }

          subscribe方法的执行流程,收到就是通过SubscriberMethod中的eventType 获取事件类型,然后封装一个Subscription实例,我们知道EventBus类中维护这个一个key为事件类型,value为Subscription集合的

     Map集合(subscriptionsByEventType),因此框架首先会从subscriptionsByEventType查找是否存在SubscriberMethod中事件类型,没有的话就创建一个CopyOnWriteArrayList<Subscription>subscriptions并添加到 subscriptionsByEventType集合中;

        由于EventBus框架支持事件的排序,因此根据 subscriberMethod.priority 来进行排序添加;当EventBus框架接收到事件后,就会从subscriptionsByEventType取出所有支持事件类型的Subscription,并依此进行分发;

        在框架进行subscribe时,还会将订阅者实例中所有支持的消息事件监听函数添加到EventBus类中的typesBySubscriber列表中,主要目的是当解除绑定时加快查找的效率;

        EventBus框架是支持粘性事件的,EventBus 将最新的粘性事件保存在内存中,性事件可以被传递给订阅者或显示查询。因此,你不需要任何特殊逻辑去获取已有的数据。

       当消息监听函数中的“Subscribe”注解中的sticky==true时,则这个监听函数就是个粘性事件的处理函数;在 EventBus框架中,在订阅者进行subscribe时就进行粘性事件的分发,由于粘性事件是存储在stickyEvents集合中,依此遍历去执行这个粘性事件;具体的事件分发方式是和普通的事件分发是一样的;

    事件解绑

       事件的解绑非常的简单,只需要调用EventBus框架的unregister方法就可以,在unregister方法内部,首先通过方法参数中的订阅者实例查找EventBus类中的typesBySubscriber列表,查找出所支持的所有支持的消息监听函数,然后在依此从subscriptionsByEventType列表中移除,最后从typesBySubscriber移除;

    public synchronized void unregister(Object subscriber) {
            List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
            if (subscribedTypes != null) {
                for (Class<?> eventType : subscribedTypes) {
                    unsubscribeByEventType(subscriber, eventType);
                }
                typesBySubscriber.remove(subscriber);
            } else {
                Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
            }
        }

     

  • 相关阅读:
    洛谷 P1939 矩阵加速(数列)
    【模板】矩阵快速幂
    洛谷 P3128 [USACO15DEC]最大流Max Flow
    洛谷 P1967 货车运输
    【模板】最近公共祖先(LCA)
    【模板】高斯消元法
    java从基础知识(七)java集合
    java基础知识(六)日期处理
    java基础知识(五)java类
    会员体系-系统豆的获取与消费
  • 原文地址:https://www.cnblogs.com/h20064528/p/6763880.html
Copyright © 2011-2022 走看看