Android EventBus源码解析

你离开我真会死。 提交于 2020-03-10 09:31:47

前言

上一篇文章自己对EventBus的用法进行了简单的叙述,然后自己又去研究了一下EventBus3.0源码也参考了网上的一些大佬的博客进行进一步的理解,写这一篇文章让自己对EventBus有个好的总结回顾,如有不正确的地方欢迎留言。

一、EventBus简介

在EventBus没出现之前,那时候的开发者一般是使用Android四大组件中的广播进行组件间的消息传递,那么我们为什么要使用事件总线机制来替代广播呢?主要是因为:

广播:耗时、容易被捕获(不安全)。
事件总线:更节省资源、更高效,能将信息传递给原生以外的各种对象。

关于事件其实是一个泛泛的统称,指的是一个概念上的东西(不一定非得用什么Event命),通过查阅官方文档,事件的命名格式并没有任何要求,你可以定义一个对象作为事件,也可以发送基本数据类型如int,String等作为一个事件。后续的源码也可以进步证明(方法的命名并没有任何要求,只是加上@Subscribe注解即可!同时事件的命名也没有任何要求)。

EventBus作为一个消息总线主要有三个组成部分:
事件(Event): 可以是任意类型的对象。通过事件的发布者将事件进行传递。
事件订阅者(Subscriber): 接收特定的事件。
事件发布者(Publisher): 用于通知 Subscriber 有事件发生。可以在任意线程任 意位置发送事件。
图1
上图1解释了整个EventBus的大概工作流程:事件的发布者(Publisher)将事件 (Event)通过post()方法发送。EventBus内部进行处理,找到订阅了该事件 (Event)的事件订阅者(Subscriber)。然后该事件的订阅者(Subscriber)通过 onEvent()方法接收事件进行相关处理。

二、EventBus源码解析

1、订阅者:EventBus.getDefault().register(this);

首先,我们从获取EventBus实例的方法getDefault()开始分析:

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

在getDefault()中使用了双重校验并加锁的单例模式来创建EventBus实例。
接着,我们看到EventBus的默认构造方法中做了什么:

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

public EventBus() {
    this(DEFAULT_BUILDER);
}

在EventBus的默认构造方法中又调用了它的另一个有参构造方法,将一个类型为EventBusBuilder的DEFAULT_BUILDER对象传递进去了。这里的EventBusBuilder很明显是一个EventBus的建造器,以便于EventBus能够添加自定义的参数和安装一个自定义的默认EventBus实例。
我们再看一下EventBusBuilder的构造方法:

public class EventBusBuilder {

    ...

    EventBusBuilder() {
    }
    
    ...
    
}

EventBusBuilder的构造方法中什么也没有做,那我么继续查看EventBus的这个有参构造方法:

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
private final Map<Object, List<Class<?>>> typesBySubscriber;
private final Map<Class<?>, Object> stickyEvents;

EventBus(EventBusBuilder builder) {
    ...
    
   //Map<订阅事件, 订阅该事件的订阅者集合> 键为 Event的类类型(也就是定义订阅方法里面的实体类型),值为元素 Subscription(订阅信息)链表
   //Subscription 类:关注类中两个字段,一个是 Object 类型的 subscriber,该字段即为注册的对象(在 Android 中时常为 Activity) 
   //另一个是 SubscriberMethod 类型,细节如下:
   //subscriberMethod:SubscriberMethod 类型(订阅方法)。关注类中有个字段 eventType 是 Class<?> 类型,代表 Event 的类类型。
    subscriptionsByEventType = new HashMap<>();
    
    // Map<订阅者, 订阅事件集合> (举个例子就是Activity中对应着该Activity中所有的对应的订阅方法)
    typesBySubscriber = new HashMap<>();
    
    // Map<订阅事件类类型,订阅事件实例对象>. 专用于粘性事件处理的一个字,用于判断某个对象是否注册过.
    stickyEvents = new ConcurrentHashMap<>();
    
    //mainThreadPoster:主线程事件发送器,通过它的mainThreadPoster.enqueue(subscription, event)
    //方法可以将订阅信息和对应的事件进行入队,
	//然后通过 handler 去发送一个消息,在 handler 的 handleMessage 中去执行方法。 
    mainThreadSupport = builder.getMainThreadSupport();
    mainThreadPoster = mainThreadSupport != null ? 
    mainThreadSupport.createPoster(this) : null;
    //backgroundPoster:后台事件发送器,通过它的enqueue() 将方法加入到后台的一个队列,
	//最后通过线程池去执行,注意,它在 Executor的execute()方法 上添加了 synchronized关键字 
	//并设立了控制标记flag,保证任一时间只且仅能有一个任务会被线程池执行。
    backgroundPoster = new BackgroundPoster(this);
    //asyncPoster:实现逻辑类似于backgroundPoster,不同于backgroundPoster的保证
	//任一时间只且仅能有一个任务会被线程池执行的特性,asyncPoster则是异步运行的,可以同时接收多个任务
    asyncPoster = new AsyncPoster(this);
    
    ...
    
    
    subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
            builder.strictMethodVerification, builder.ignoreGeneratedIndex);
   
    // 从builder取中一些列订阅相关信息进行赋值
    ...
   
    // 从builder中取出了一个默认的线程池对象,它由Executors的newCachedThreadPool()方法创建,它是一个有则用、无则创建、无数量上限的线程池。
    executorService = builder.executorService;
}

下面看具体的register()中执行的代码。

  public void register(Object subscriber) { 
         //订阅者类型 
         Class<?> subscriberClass = subscriber.getClass(); 
         //判断该类是不是匿名类,如果是匿名类要使用反射 
         boolean forceReflection = subscriberClass.isAnonymousClass(); 
         //获取订阅者全部的响应函数信息(即上面的onNewsEvent()之类的方法) 
         List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(sub scriberClass, forceReflection); 
        //循环每一个事件响应函数,执行 subscribe()方法,更新订阅相关信息 
        for (SubscriberMethod subscriberMethod : subscriberMetho ds) { subscribe(subscriber, subscriberMethod); 
        } 
  }

接着我们查看SubscriberMethodFinder的findSubscriberMethods()方法:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    // METHOD_CACHE:Map<Class<?>, List<SubscriberMethod>> 类型。键为注册类的 Class(例如:Activity),
    //值为该类中所有 EventBus 回调的方法链表(也就是被 @Subscribe 标记的方法们)。
    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
    if (subscriberMethods != null) {
        return subscriberMethods;
    }

    //ignoreGeneratedIndex 来判断是否使用生成的 APT 代码去优化寻找接收事件的过程,如果开启了的话,
	//那么将会通过 subscriberInfoIndexes 来快速得到接收事件方法的相关信息。
	//所以各位读者如果没有在项目中接入 EventBus 的 APT,
	//那么可以将 ignoreGeneratedIndex 设为 false 提高性能
    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;
    }
}

在这里我们假如ignoreGeneratedIndex为true,看下findUsingReflection()方法

private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
    	// 通过纯反射去获取被 @Subscribe 所修饰的方法
        findUsingReflectionInSingleClass(findState);
        // 将当前 class 的父类 class 赋值给 findState.clazz 
        findState.moveToSuperclass();
    }
    // 重置 FindState 便于下一次回收利用
    return getMethodsAndRelease(findState);
} 
初始化 FindState 对象后,会进入一个 while 循环中,不停地去反射获取当前类和其父类(注意,在 Java 中,如果当前类实现了一个接口,即使该接口的方法被 @Subscribe 所修饰,当前类中的方法也是不包含该注解属性的,所以如果在接口中对某个方法使用了 @Subscribe 修饰然后让类去实现这个接口是没有任何作用的)的订阅方法并添入列表中,最终返回这个列表并重置 FindState 对象利于下一次重复使用。```

这里ignoreGeneratedIndex 默认为false,所以会执行findUsingInfo()方法

```java
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    // 注释1处
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
    	// 注释2处
        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 {
             // 注释3处
             findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();
    }
    // 重置 FindState 便于下一次回收利用
    return getMethodsAndRelease(findState);
}

注释1处: SubscriberMethodFinder中的prepareFindState()方法:

//会先从 FIND_STATE_POOL 即 FindState 池中取出可用的 FindState(这里的POOL_SIZE为4),
//如果没有的话,则通过代码直接新建 一个新的 FindState 对象。
//由于 FindState 在注册流程中使用频繁且创建耗费资源,故创建 FindState 池复用 FindState 对象
private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];
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();
}

分析下FindState这个类:

static class FindState {
    ....
    void initForSubscriber(Class<?> subscriberClass) {
        this.subscriberClass = clazz = subscriberClass;
        skipSuperClasses = false;
        subscriberInfo = null;
    }
    ...
}

它是 SubscriberMethodFinder 的内部类,这个方法主要做一个初始化、回收对象等工作。

我们在回到SubscriberMethodFinder注释2处:getSubscriberInfo():

private SubscriberInfo getSubscriberInfo(FindState findState) {
    if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
        SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
        if (findState.clazz == superclassInfo.getSubscriberClass()) {
            return superclassInfo;
        }
    }
    if (subscriberInfoIndexes != null) {
        for (SubscriberInfoIndex index: subscriberInfoIndexes) {
            SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
            if (info != null) {
                return info;
            }
        }
    }
    return null;
}

这里由于初始化的时候,findState.subscriberInfo和subscriberInfoIndexes为空,所以这里直接返回null
接着我们查看注释3处的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");
        }
    }
}

这个方法的逻辑是:
通过反射的方式获取订阅者类中的所有声明方法,然后在这些方法里面寻找以@Subscribe作为注解的方法进行处理,先经过一轮检查,看看findState.subscriberMethods是否存在,如果有的话,将方法名,threadMode,优先级,是否为sticky方法封装为SubscriberMethod对象,添加到subscriberMethods列表中。
而实际上是需要过滤一遍的,讲解 checkAdd() 源码前,请思考以下几个问题:
对于同一个 Event,当前类对该对象使用了多个方法进行了多次订阅,那么如果该 Event 被发射的时候,当前类会如何调用这些方法?
对于同一个 Event,父类对该对象进行了一次订阅,子类重写该订阅方法,那么如果该 Event 被发射的时候,父类子类当中会如何处理这些方法?
解决这些方法就需要去看看 checkAdd() 的底层实现了:

boolean checkAdd(Method method, Class<?> eventType) {
    Object existing = anyMethodByEventType.put(eventType, method);
    if (existing == null) {
        return true;
    } else {
        return checkAddWithMethodSignature(method, eventType);
    }
}

可以看到 anyMethodByEventType 使用了 Event 的 Class 作为键,这像是意味着一个类对于同一个 Event 只能订阅一次,事实上是不是这样,还得继续看看 checkAddWithMethodSignature(),其源码简化如下:

private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
    methodKeyBuilder.setLength(0);
    methodKeyBuilder.append(method.getName());
    methodKeyBuilder.append('>').append(eventType.getName());

    String methodKey = methodKeyBuilder.toString();
    Class<?> methodClass = method.getDeclaringClass();
    Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
    if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
        return true;
    } else {
        subscriberClassByMethodKey.put(methodKey, methodClassOld);
        return false;
    }
}

可以看到 subscriberClassByMethodKey 使用方法名 + ‘>’ + 事件类型作为键,这意味着对于同一个类来说,subscriberClassByMethodKey 肯定不会键重复(毕竟一个类中不能够方法名相同且方法参数、个数都相同),因此它最终会返回 true。这意味着一个类如果使用了多个方法对同一个 Event 对象进行注册,那么当该 Event 对象被发射出来的时候,所有的方法都将会得到回调。
但是当父类执行上述操作的时候,如果子类有「显示」实现父类的订阅方法,那么此时 subscriberClassByMethodKey.put(methodKey, methodClass) 返回值不会为空,且为子类的 Class,此时 if 上分支将会判断子类 Class 是否 isAssignableFrom 父类 Class,这肯定是会为 false 的,这将会走入 if 下分支并返回 false。这意味着当子类「显示」实现父类的订阅方法的时候,如果此时发射指定 Event 的话,父类的订阅方法将不会执行,而仅会执行子类的订阅方法。

返回subscriberMethods之后,register方法的最后会调用subscribe方法:

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
	//获取订阅的事件类型 
    Class<?> eventType = subscriberMethod.eventType;
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    //获取订阅该事件的订阅者集合 在subscriptionsByEventType去查找一个CopyOnWriteArrayList ,
    //如果没有则创建一个新的CopyOnWriteArrayList
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
     //把通过register()订阅的订阅者包装成Subscription 对象 Subscription newSubscription 
    //= new Subscription(subscrib er, subscriberMethod); 
    //订阅者集合为空,创建新的集合,并把newSubscription 加入
    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();
    //添加 newSubscription对象,它是一个 Subscription 类,里面包含着 subscriber 和 subscriberMethod 等信息,
	//并且这里有一个优先级的判断,说明它是按照优先级添加的。优先级越高,会插到在当前 List 靠前面的位置
    for (int i = 0; i <= size; i++) {
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
        // 根据 priority 大小放入 List 中
            subscriptions.add(i, newSubscription);
            break;
        }
    }
    //对typesBySubscriber 进行添加,这主要是在EventBus的isRegister()方法中去使用的,目的是用来判断这个 Subscriber对象 是否已被注册过
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);
    //会判断是否是 sticky事件。如果是sticky事件的话,会调用 checkPostStickyEventToSubscription() 方法
    if (subscriberMethod.sticky) {
    	//响应订阅事件的父类事件 
        if (eventInheritance) {
            Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
            //循环获得每个stickyEvent事件 
            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);
        }
    }
}

我们来看下checkPostStickyEventToSubscription()方法:

private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
    if (stickyEvent != null) {
        postToSubscription(newSubscription, stickyEvent, isMainThread());
    }
}

可以看到最终是调用了postToSubscription()这个方法来进行粘性事件的发送,对于粘性事件的处理,我们最后再分析,接下来我们看看事件是如何post的。

2、发布者:EventBus.getDefault().post(new Event());

先来看下post()方法:

public void post(Object event) {
    //
    PostingThreadState postingState = currentPostingThreadState.get();
    List <Object> eventQueue = postingState.eventQueue;
    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);
            }
        } finally {
            postingState.isPosting = false;
            postingState.isMainThread = false;
        }
    }
}

currentPostingThreadState 是一个 ThreadLocal 类,通过它获取到 PostingThreadState 对象,再根据该对象获取到 event 链表(有没有联想到 Android 中的消息机制?),并将传入的 event 塞入该链表。为了控制 Event 出队列不会被调用多次,PostingThreadState 对象有一个 isPosting 来标记当前链表是否已经开始进行回调操作,通过源码可以看到,每次分发完一个 Event 事件,该事件也会被从链表中 remove 出去。可以看下currentPostingThreadState的源码如下:

private final ThreadLocal <PostingThreadState> currentPostingThreadState = new ThreadLocal <PostingThreadState> () {
@Override
protected PostingThreadState initialValue() {
    return new PostingThreadState();
}
};

final static class PostingThreadState {
    final List <Object> eventQueue = new ArrayList<>();
    boolean isPosting;
    boolean isMainThread;
    Subscription subscription;
    Object event;
    boolean canceled;
}

下一步进入postSingleEvent()方法

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
	//分发事件的类型
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;
    //默认为true,如果设为 true 的话,它会在发射事件的时候判断是否需要发射父类事件,设为 false,能够提高一些性能。
    if (eventInheritance) {
        //它的作用就是取出 Event 及其父类和接口的 class 列表,当然重复取的话会影响性能,
        //所以它也做了一个 eventTypesCache 的缓存,这样就不用重复调用 getSuperclass() 方法。
        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);
    }
    if (!subscriptionFound) {
        ...
    }
}

然后我们在进入postSingleEventForEventType()方法:

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class <?> eventClass) {
    CopyOnWriteArrayList <Subscription> subscriptions;
    synchronized(this) {
     // 获取订阅事件类类型对应的订阅者信息集合.(register函数时构造的集 合) 
        subscriptions = subscriptionsByEventType.get(eventClass);
    }
    if (subscriptions != null && !subscriptions.isEmpty()) {
        for (Subscription subscription: subscriptions) {
            postingState.event = event;
            postingState.subscription = subscription;
            boolean aborted = false;
            try {
            // 发布订阅事件给订阅函数
                postToSubscription(subscription, event, postingState.isMainThread);
                aborted = postingState.canceled;
            } finally {
                postingState.event = null;
                postingState.subscription = null;
                postingState.canceled = false;
            }
            if (aborted) {
                break;
            }
        }
        return true;
    }
    return false;
}

这里直接根据 Event 类型从 subscriptionsByEventType 中取出对应的 subscriptions对象,最后调用了 postToSubscription() 方法。

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 MAIN_ORDERED:
            if (mainThreadPoster != null) {
                mainThreadPoster.enqueue(subscription, event);
            } else {
                invokeSubscriber(subscription, event);
            }
            break;
        case BACKGROUND:
            if (isMainThread) {
                backgroundPoster.enqueue(subscription, event);
            } else {
                invokeSubscriber(subscription, event);
            }
            break;
        case ASYNC:
            asyncPoster.enqueue(subscription, event);
            break;
        default:
            throw new IllegalStateException("Unknow thread mode: " + subscription.subscriberMethod.threadMode);
    }
}

其实可以发现只用到了两种方法,一种是 invokeSubscriber 意味着立即调用该方法,另一种是 xxxPoster.enqueue() 意味着需要使用其他线程来执行该方法。
以下是threadMode 哪几种应避免耗时操作,耗时时阻塞的是哪条线程:

  • POSTING:接收事件方法应执行在发射事件方法所在的线程(由于发射事件方法线程可能是主线程,这意味着接收方法不能执行耗时操作,否则会阻塞主线程)
  • MAIN:在 Android 中则接收事件方法应执行在主线程,否则(在 Java 项目中)等同于 POSTING。如果发射事件方法已位于主线程,那么接收事件方法会被「立即」调用(这意味着接收事件方法不能执行耗时操作,否则会阻塞主线程;同时,由于是「立即」调用,所以发射事件方法此时是会被接收事件方法所阻塞的),否则等同于 MAIN_ORDERED
  • MAIN_ORDERED:在 Android 中则接收事件方法会被扔进 MessageQueue 中等待执行(这意味着发射事件方法是不会被阻塞的),否则(在 Java 项目中)等同于 POSTING。
  • BACKGROUND:
    • 在 Android 中
      • 发射事件方法在主线程中执行,则接收事件方法应执行在子线程执行,但该子线程是 EventBus 维护的单一子线程,所以为了避免影响到其他接收事件方法的执行,该方法不应太耗时避免该子线程阻塞。
      • 发射事件方法在子线程中执行,则接收事件方法应执行在发射事件方法所在的线程。
    • 在 Java 项目中,接收事件方法会始终执行在 EventBus 维护的单一子线程中。
  • ASYNC:接收方法应执行在不同于发射事件方法所在的另一个线程。常用于耗时操作,例如网络访问。当然,尽量避免在同一个时间大量触发此类型方法,尽管 EventBus 为此专门创建了线程池来管理回收利用这些线程。

3、解除订阅:EventBus.getDefault().unregister(this);

  public synchronized void unregister(Object subscriber) { 
     // 获取该订阅者所有的订阅事件类类型集合. 
     List<Class<?>> subscribedTypes = typesBySubscriber.get(subsc riber); 
     if (subscribedTypes != null) { 
         for (Class<?> eventType : subscribedTypes) { 
         	//subscriptionsByEventType 移除了该 subscriber 的所有订阅信息
              unsubscribeByEventType(subscriber, eventType); 
         }
         // 从typesBySubscriber删除该<订阅者对象,订阅事件类类型集合> 
         typesBySubscriber.remove(subscriber); 
     } else { 
         Log.e("EventBus", "Subscriber to unregister was not regi stered before: "+ subscriber.getClass()); 
     } 
  }
  private void unsubscribeByEventType(Object subscriber, Class<?> eventType) { 
     // 获取订阅事件对应的订阅者信息集合. 
     List<Subscription> subscriptions = subscriptionsByEventType. get(eventType); 
     if (subscriptions != null) { 
         int size = subscriptions.size(); 
         for (int i = 0; i < size; i ++) { 
              Subscription subscription = subscriptions.get(i); 
              // 从订阅者集合中删除特定的订阅者. 
              if (subscription.subscriber == subscriber) { 
                  subscription.active = false; 
                  subscriptions.remove(i); 
                  i --; 
                  size --; 
              } 
         } 
     } 
  }

4、发布黏性瞬间:EventBus.getDefault.postSticky(new CollectEvent())

普通事件是先注册,然后发送事件才能收到;而粘性事件,在发送事件之后再订阅该事件也能收到。此外,粘性事件会保存在内存中,每次进入都会去内存中查找获取最新的粘性事件,除非你手动解除注册

public void postSticky(Object event) {
    synchronized (stickyEvents) {
        // 先将该事件放入 stickyEvents 中
        stickyEvents.put(event.getClass(), event);
    }
    post(event);
}

可以看到第一步是将该事件放入 stickyEvents 中,第二步则是正常 post()。为避免多线程操作 postSticky(Object) 和 removeStickyEvent(Class<?>) 引发的冲突,所以对 stickyEvents 对象添加了 synchronized 关键字,
前面我们在分析register()方法的最后部分时,其中有关粘性事件的源码如下:

if (subscriberMethod.sticky) {
    Object stickyEvent = stickyEvents.get(eventType);
    if (stickyEvent != null) {
        postToSubscription(newSubscription, stickyEvent, isMainThread());
    }
}

可以看到,在这里会判断当前事件是否是 sticky 事件,如果是,则从 stickyEvents 中拿出该事件并执行 postToSubscription() 方法。

好了EventBus源码到此结束了。

总结

EventBus 源码都说简单我可没看出简单啊,当中的很多设计技巧是非常值得学习的,例如前文提到的复用池,以及遍布 EventBus 源码各处的 synchronized 关键字。笔者也是第一次写源码的分析,也是借鉴网上的大佬们的文章。

参考链接:
Android主流三方库源码分析(九、深入理解EventBus源码)
聊一聊 EventBus 源码和设计之禅
EventBus 3.1.1 源码解析

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!