天天看点

EventBus源码解析(3.1.1版本)EventBus源码解析(3.1.1版本)

EventBus源码解析(3.1.1版本)

核心思想:

EventBus之所以能在不同线程,不同组件之间进行通信,核心思路是:

1.维护一个单例,使得不同线程,不同组件操作的都是这个整个程序全局的EventBus对象。

2.注册处理方法,将其参数类型、当前所在的类的对象、当前类的class对象对应的方法等等信息保存起来,存放在全局的EventBus中。

使得不同线程,不同组件都可以很轻易拿到这些信息

3.在发送信息的地方,通过发送的参数类型,取到注册时也为此参数类型的方法(可以有多个),通过反射对这些方法进行调用。

基本用法

1.需要触发的地方注册方法

EventBus.getDefault().register(this);           

2.注册的处理事件

@Subscribe (ThreadMode = ThreadMode.MAIN)  
public void XXX(Event event){
      ……
}           

3.发送事件

EventBus.getDefault().post(event);           

getDefault()

  • 通过核心思想的分析,可以很容易的猜出这个方法,就是一个单例方法维护整个程序的一个 EventBus 对象。
public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }           

register()

首先应该知道

1.这个方法便是我们核心思想中的第二点,主要是将所有的需要的信息都保存起来

2.为什么要保存起来呢?

 答:我们最终要用反射去调用需要触发的方法:

  

method.invoke(类的对象,参数类型);

  为此我们就需要在发送事件的地方,也能取到method、注册类的对象、参数类型。

 所以,需要保存到全局的对象中。

正式进入代码

public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();//1
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);//2
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);//3
            }
        }
    }           
  • 注释1 处取到了我们反射需要的 注册类的class对象
  • 2 处最终返回了 注册类 里注册的 触发方法集合
  • 3 处遍历触发方法集合,每个都调用 subscribe 方法将 注册类的对象 、相应的method、参数类型 都关联并保存起来

看看注释3处是怎么保存的(subscribe方法):

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType;//2
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);//1
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);//2
        if (subscriptions == null) {//3
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            ……
        }


        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);//4
                break;
            }
        }


        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);


        if (subscriberMethod.sticky) {//5
            ……
        }
    }           

讲解前不得不先提到几个变量:

1.

Subscription

订阅对象

保存了各种订阅信息的对象

2.

CopyOnWriteArrayList<Subscription> subscriptions

实现List接口

subscription对象集合

3.

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;

Map集合

key:eventType(参数类型);value:CopyOnWriteArrayList(Subscription)

回到代码

* 注释1处,将 subscriber(注册类的对象) 和 subscriberMethod(订阅方法) 作为参数创建一个 Subscription

* 第一个2处将已经保存在订阅方法中的 参数类型eventType 取出。

* 第二个2处以 eventType 为 key 取到 订阅对象集合CopyOnWriteArrayList

* 3处为缓存的使用,如果没有缓存,就以 eventType为key,subscriptions为value保存起来

* 4处将订阅对象以订阅方法优先级保存到 CopyOnWriteArrayList 中

* 5处是对粘性事件的处理,这里不做分析

回到register中的注释2(findSubscriberMethods方法)中:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);//1
        if (subscriberMethods != null) {
            return subscriberMethods;
        }


        if (ignoreGeneratedIndex) {
            subscriberMethods = findUsingReflection(subscriberClass);
        } else {
            subscriberMethods = findUsingInfo(subscriberClass);//3
        }
        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);//2
            return subscriberMethods;
        }
    }           
  • 注释1处看看缓存中有没有注册类对应的订阅方法集合,有就直接返回;没有就各种逻辑取到后在2处保存到缓存中
  • ignoreGeneratedIndex 一般为 false(调用 getDefault 方法获取单例时为 false)
  • 所以,一般执行3

findUsingInfo

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);//1
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);
            if (findState.subscriberInfo != null) {
                SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();//2
                for (SubscriberMethod subscriberMethod : array) {
                    if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
                        findState.subscriberMethods.add(subscriberMethod);
                    }
                }
            } else {
                findUsingReflectionInSingleClass(findState);//3
            }
            findState.moveToSuperclass();
        }
        return getMethodsAndRelease(findState);//4
    }           
  • 1处将 注册类的class对象 赋值到查找工具类 FindState 中:
void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
                ……
        }           
  • 2处不做分析
  • 一般执行3处(里面找到订阅方法并将其保存到 findState 的 subscriberMethods 变量 中)
  • 4实际上是将 findState 里的 subscriberMethods变量 生成 List集合 返回

注释3处的 findUsingReflectionInSingleClass 方法

private void findUsingReflectionInSingleClass(FindState findState) {
        Method[] methods;
        try {
            methods = findState.clazz.getDeclaredMethods();//1
        } 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();//2
                if (parameterTypes.length == 1) {//3
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);//4
                    if (subscribeAnnotation != null) {//4
                        Class<?> eventType = parameterTypes[0];
                        if (findState.checkAdd(method, eventType)) {
                            ThreadMode threadMode = subscribeAnnotation.threadMode();//5
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));//6
                        }
                    }
                } ……
                }
            } ……
        }           
  • 注释1处拿到注册类里的所有方法(注册类的class对象 对应的方法)
  • 遍历,在2处反射拿到每个方法的参数
  • 3处过滤掉所有参数不是1个的方法(说明我们的订阅方法参数应该定义为1个)
  • 第一个4处反射拿到 Subscribe 注解,第二个4处判断如果注释不为空,则找到我们的订阅方法
  • 5拿到注解里声明的参数 threadMode
  • 6用方法(method)、方法类型(eventType)、注解声明的线程模型(ThreadMode)等参数生成一个订阅方法对象(SubscriberMethod)。再添加到 findState 的订阅方法集合中。

然后回到findUsingInfo的注释4处

private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
        List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
        ……
        return subscriberMethods;
    }           
  • 将 findState 的订阅方法集合生成新的 list 返回

post()

首先应该知道

这个方法是核心思想里的第三点,主要是通过参数类型获得对应的method,最后通过反射进行调用

正式进入代码

public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();//1
        List<Object> eventQueue = postingState.eventQueue;//2
        eventQueue.add(event);


        if (!postingState.isPosting) {
            postingState.isMainThread = isMainThread();
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                while (!eventQueue.isEmpty()) {
                    postSingleEvent(eventQueue.remove(0), postingState);//3
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
           
  • 1处的 PostingThreadState 里保存了事件队列和线程状态信息。
  • 2处将事件队列取出,再把事件添加进去
  • 3处将队列中的事件依次由 postSingleEvent 方法处理,每次都将list第0个位置的事件移除并传入,就可以实现队列的“先进先出”的效果。

postSingleEvent

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        if (eventInheritance) {
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);//1
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);//2
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {
            ……
        }
    }           
  • eventInheritance 表示是否向上查找事件的父类,默认为true
  • true时,执行1处代码,也即是通过 lookupAllEventTypes 找到所有的父类事件存在list中
  • 再对 list 里的所有事件逐一进行 postSingleEventForEventType 处理

    这里有什么意义呢:

    假如,post(new A());

    class A extends B implement C{}

    那么如果在一个类中注册了 void xxx(A a){}、 void xxx(B b){}、void xxx(C c){} 三个方法

    post一次,这三个方法都会触发。

postSingleEventForEventType

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);//1
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;
                try {
                    postToSubscription(subscription, event, postingState.isMainThread);//2
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }           
  • 首先,确认下三个参数的意思:

    event: post 时传入的事件参数,最终当做反射invoke(,)传入的第二个参数

    postingState: 保存事件队列和线程状态信息

    eventClass: 事件和其父类对应的 class 对象,用来取到 register 时保存在 map 中对应的订阅方法

  • 1处通过 key(事件的class对象) 从执行 register 过程中维护的 map 中取到对应的 subscriptions(订阅对象集合)
  • 随之遍历,将 event 和 subscription 传给 postingState
  • 2处为核心处理方法

postToSubscription

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                if (isMainThread) {//1
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    ……
                } else {
                    ……
                }
                break;
            case BACKGROUND:
                if (isMainThread) {
                    ……
                } else {
                    ……
                }
                break;
            case ASYNC:
                ……
            default:
                ……
        }
    }           
  • 首先明确下参数:

    subscription:订阅对象,包含了注册的类的对象、订阅方法等信息

    event:事件参数

    isMainThread:发送时所在的线程是否为主线程。(通过Looper.getMainLooper == Looper.myLooper()判断)

  • 1处,线程模型为 MAIN 时(哪个线程触发事件)。判断发送时所在的线程是否是主线程
  • 如果是,则执行 invokeSubscriber ,若不是,则通过 mainThreadPoster 将订阅事件添加到主线程队列中。(MainThreadPoster 本质是一个 Handler,通过 Handler 将订阅方法切换到主线程执行)

invokeSubscriber

void invokeSubscriber(Subscription subscription, Object event) {
        try {
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);//1
        } catch (InvocationTargetException e) {
            handleSubscriberException(subscription, event, e.getCause());
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Unexpected exception", e);
        }
    }           
  • 1处,很明显,是通过反射调用订阅方法,传入类的对象,以及事件参数。

拓展

  • 因为EventBus是通过参数类型判断哪个方法触发。
  • 那么我们如果在同一个类中注册名字不同,但是参数相同的两个方法,post这个参数一次,这两个方法都会被调用。

继续阅读