由浅入深了解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());
        }
    }

 

 

 

posted @ 2017-04-26 10:57  飞蛾扑火  阅读(196)  评论(0编辑  收藏  举报