Android进阶 -- EventBus源码解析(一)

在发送的消息的时候,会通过EventBus.getDefault().register()进行调用,先来看下EventBus.getDefault()方法

public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }

很明显是一个DLC的单例模式,但是在往下的看的时候,发现EventBus并没有设计私有的构造方法

public EventBus() {
        this(DEFAULT_BUILDER);
}

 也就是说,通过new的方法,也可以获取EventBus实例,但是建议使用EvnentBus.getDefault()的方式来获取实例,通过一个实例来管理所有的事件

再来看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);
            }
        }
}

一般register传进来的是Activity对象,首先通过getClass方法获取到Activity的Class对象,然后把这个class对象又传递给了findSubscriberMethods方法,这个方法是用来从订阅类中获取所有的订阅方法信息,订阅者其实就是传进来的Activity,通过这个方法,可以获取到所有在此Activity中注册的方法。

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        List<SubscriberMethod> 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;
        }
}

 List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);首先通过传进来的Class对象在缓存中去获取

if (subscriberMethods != null) {return subscriberMethods;} 如果缓存中有这些方法,就直接返回

如果缓存中没有,就根据ignoreGeneratedIndex的值,来判断使用哪个方法去获取

方法1:findUsingReflection(subscriberClass) 利用反射来获取订阅类中的订阅方法信息,这里subscriberClass是注册事件的Activity,通过反射,可以拿到它的全部方法,包括我们需要的订阅方法,但此时效率较低

方法2:findUsingInfo(subscriberClass);从注解器生成的类中获得订阅类的订阅方法信息,因为在Activity里只有订阅方法会加注解,所以此时效率较高,ignoreGeneratedIndex值默认为false,即默认使用注解器生成的类中去获取订阅方法

最后两行代码比较简单,如果没有获取到就抛出异常,如果获取到就写近缓存,方便下次获取。

在来看通过注解器获取的方法findUsingInfo(subscriberClass)

private List<SubscriberMethod> 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 findState = prepareFindState();用来从FIND_STATE_POOL中查找状态,先来看看prepareFindState这个方法

private FindState prepareFindState() {
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                FindState state = FIND_STATE_POOL[i];
                if (state != null) {
                    FIND_STATE_POOL[i] = null;
                    return state;
                }
            }
        }
        return new FindState();
}

这个状态池类似于线程池机制,避免重复创建销毁,用来提高性能。再回到findUsingInfo(subscriberClass)方法,获取到状态之后,进行初始化。由于findState.subscriberInfo默认为null,所以进入findUsingReflectionInSingleClass(findState)方法,这个方法用来获取订阅的方法

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();
            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");
            }
        }
    }

findUsingReflectionInSingleClass这个方法相对比较长,但是逻辑简单,首先通过getDeclaredMethods去获取,如果获取不到,就通过getMethods获取所有公用方法,然后进行循环,循环体里有两个条件判断

条件一:modifiers & Modifier.PUBLIC) != 0,即EventBus的订阅方法必须用public来修饰

条件二:parameterTypes.length == 1,即EventBus的订阅方法只能有一个参数

然后再通过checkAdd来判断,如果没有添加过此方法,就添加,如果添加过,就不添加。至此,EventBus已经拿到了我们在该类里声明的所有订阅方法,然后返回到register方法里的 List<SubscriberMethod> subscriberMethods,接着会执行register方法里的subscribe方法,即将该Activity里的所有方法,汇总到EventBus事件总线里。看看register里的subscribe(subscriber, subscriberMethod)方法,第一个参数subscriber订阅者,就是当前的Activity,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) {
                // 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);
            }
        }
    }

首先通过Class<?> eventType = subscriberMethod.eventType拿到订阅方法的事件类型,CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType)拿到EventBus事件总线里的所有该事件类型的订阅者,然后通过 subscriptionsByEventType.put(eventType, subscriptions)方法将订阅者添加到该事件总线中,在然后将当前订阅者的所有订阅事件类型添加到typesBySubscriber中。

至此,register的原理就分析完了,这里要关注两个Map

subscriptionsByEventType : 即EventBus的事件总线,里面根据事件类型存放了所有的订阅者(如String事件类型的AActivity、BActivity等)

typesBySubscriber:即当前订阅者的所有订阅事件信息(如AActivity的String事件、du),方便在onDestory的时候释放

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值