Android进阶之路 —EventBus源码解析

EventBus是基于发布/订阅的开源框架,主要用于组件之间的通信,下面会从三个点对EventBus的源码进行分析

(1)register(Object subscriber) 被通知类的注册

使用EventBus时我们首先会在需要被通知的类中去进行注册,现在看一下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中会通过findSubscriberMethods方法得到一个SubscriberMethod的列表,来看一下查找方法的实现。

 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;
        }
    }

方法内部首先会以subscriberClass,也就是注册的类对象为key,在METHOD_CACHE中查找对应的SubscriberMethod集合,如果有则返回,没有的话则会通过两种方式去查找,一种是通过反射的方法,另一种是通过索引文件的方式,这边只看使用反射方式查找并缓存。

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

//精简之后的代码
 private void findUsingReflectionInSingleClass(FindState findState) {
        methods = findState.clazz.getDeclaredMethods();
        for (Method method : methods) {
          findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
        }
    }

通过反射的方式找到目标方法集合,然后遍历集合将method、eventType、threadMode等信息构建成一个SubscriberMethod填充到findState中,最后将SubscriberMethod的集合返回,将findState释放并放入到池中。

查找过程进行完成之后紧接着来了SubscriberMethod的遍历操作,通过subscribe方法对目标方法和类对象进行关联。

(2)post(Object event) 通知事件发送

当我们需要通信的时候,会通过post(event)的方式进行通知,然后注册的目标类就会收到相应的通知。

public void post(Object event) {
       // 省略n行代码
            try {
                while (!eventQueue.isEmpty()) {
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

方法内部就是通过postSingleEvent方法进行事件发送,继续跟进这个方法。

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        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 {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
    }

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
            for (Subscription subscription : subscriptions) {
                postToSubscription(subscription, event, postingState.isMainThread);
    }

通过event找到关联的类集合,通过postToSubscription方法遍历的对目标类进行通知。

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        //省略。。。
        invokeSubscriber(subscription, event);
    }

最后通过反射的方式对目标方法进行调用

(3)ThreadMode 事件触发所在线程

在目标类中定义事件方法,一般会通过ThreadMode指定方法触发所在的线程。

在register过程中会将ThreadMode的信息封装到subscriberMethod中。来看一下具体的代码:

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 {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case BACKGROUND:
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC:
                asyncPoster.enqueue(subscription, event);
                break;
        }
    }

事件发送的时候首先会通过对ThreadMode的判断进行不同的操作。来看一下四种不同的模式有什么不同

  • MAIN

    如果post所在的线程是主线程,那么直接通过反射去调用目标方法;如果所在的线程为工作线程,则会通过Handler将线程转换到主线程中。

  • POSTING

    事件触发所在的线程与事件发送所在的线程一致

  • BACKGROUND

    如果post所在的线程是主线程,那么会重新创建一个工作线程进行方法调用;如果所在的线程为工作线程,则不会创建额外的线程,直接在当前线程中进行调用

  • ASYNC

    无论post所在的线程如何,都会额外去创建一个工作线程去进行方法调用。

这是EventBus大体的工作流程,当然还有部分细节没有去分析,有兴趣的可以自行阅读。

猜你喜欢

转载自blog.csdn.net/ww55555577/article/details/80626486