EventBus源码解析上(较详细)

305 阅读6分钟

EventBus是一个非常优秀的开源框架,具有解耦事件的发送者和接收者,简化组件间的通信,避免复杂和容易出错的依赖以及生命周期等的优点。所以对其内部源码的实现进行了一番探究。根据自己的理解,对于其注册与发送的逻辑分析,分为上下两部分。

首先需要知道的知识点

EventBus四种线程模式:

  1. ThreadMode.MAIN:表示无论事件是在哪个线程发布出来的,该事件订阅方法都会在UI线程中执行。
  2. ThreadMode.POSTING:表示事件在哪个线程中发布出来的,事件订阅方法就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。
  3. ThreadMode.BACKGROUND:表示如果事件在UI线程中发布出来的,那么订阅方法就会在子线程中运行,如果事件本来就是在子线程中发布出来的,那么订阅方法直接在该子线程中执行。
  4. ThreadMode.AYSNC:使用这个模式的订阅方法,那么无论事件在哪个线程发布,都会创建新的子线程来执行订阅方法。

带着问题看源码

  1. EventBus sticky事件的原理。
  2. EventBus 不同线程间的通知怎么做到的

首先了解几个数据结构

  1. subscriptionByEventType
    标记一个事件类型,以及其对应的订阅关系列表

     Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType
    
  2. Subscription 对订阅关系的封装

     final class Subscription {
         final Object subscriber;
         final SubscriberMethod subscriberMethod;
         volatile boolean active;   //是否处于活跃状态,经常是unregistere时,赋值为false。
     }
    
  3. SubscriberMethod 对事件接收方法的封装,包含:方法名,线程模式,事件类型(参数),优先级,是否是粘性事件几个属性

     public class SubscriberMethod {
     final Method method;
     final ThreadMode threadMode;
     final Class<?> eventType;
     final int priority;
     final boolean sticky;
     /** Used for efficient comparison */
     String methodString;
    

    }

  4. TypeBySubscriber 标记事件订阅者及其注册的接收方法的事件类型

    Map<Object, List<Class<?>>> typesBySubscriber

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

看源码

从初始化开始看起

//DCL模式的单例
public static EventBus getDefault() {
if (defaultInstance == null) {
    synchronized (EventBus.class) {
        if (defaultInstance == null) {
            defaultInstance = new EventBus();
        }
    }
}
return defaultInstance;
}

这是一个DCL模式的单例,继续往下看

//一个空的构造方法,实例创建交给了另外一个重载的构造方法
public EventBus() {
this(DEFAULT_BUILDER);
}

//这里构建EventBus的实例,有许多的参数需要构建
EventBus(EventBusBuilder builder) {
//通过参数类型标记订阅关系的数据结构
subscriptionsByEventType = new HashMap<>();
//标记一个订阅者以及订阅的参数类型的数据结构
typesBySubscriber = new HashMap<>();
//粘性事件集合
stickyEvents = new ConcurrentHashMap<>();
//事件投递者,主线程处理的handler, 唤醒订阅者进行处理
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
//事件投递者,作用同上
backgroundPoster = new BackgroundPoster(this);
//事件投递者,作用同上
asyncPoster = new AsyncPoster(this);
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
//查询订阅方法的数据结构,内部维护了一个订阅方法的集合
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
        builder.strictMethodVerification, builder.ignoreGeneratedIndex);
logSubscriberExceptions = builder.logSubscriberExceptions;
logNoSubscriberMessages = builder.logNoSubscriberMessages;
sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
throwSubscriberException = builder.throwSubscriberException;
eventInheritance = builder.eventInheritance;
executorService = builder.executorService;
}

EventBus的初始化,交给了另外一个重载的构造方法,在里面进行了很多属性的初始化,具体属性所代表的意义,已经写在了注释里。

初始化完成之后,我们继续查看Register()方法

public void register(Object subscriber) {
//1、获取当前注册的类
Class<?> subscriberClass = subscriber.getClass();
//2、获取当前类的@Subscribe注解的方法
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
//3、添加同步锁,当前注册的类绑定所有的接收方法
synchronized (this) {
    //对于该订阅者注册的每一个方法,都进行一种绑定
    for (SubscriberMethod subscriberMethod : subscriberMethods) {
        subscribe(subscriber, subscriberMethod);
    }
}
}

该方法里面进行了三步操作,第一,获取当前注册的类,第二,获取当前注册类里@Subscribe注解的方法,第三,对每一个方法,进行绑定。我们继续查看第二步findSubscriberMethods()

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//从缓存中获取所有的订阅方法,如果有,就返回
 List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
    return subscriberMethods;
}

//如果缓存没有,就继续查找,ignoreGeneratedIndex 默认为false,使用eventBus builder时会赋值该字段
if (ignoreGeneratedIndex) {
    //查询该类及其父类的@Subscribe注解的方法
    subscriberMethods = findUsingReflection(subscriberClass);
} else {
    //查询该类以及其父类的@Subscribe注解的方法
    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;
}
}

ignoreGenertatedIndex默认为false,我们继续查看findUsingInfo()方法

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//从池中取出一个findState对象
FindState findState = prepareFindState();  //注释1
//将订阅者传递给findState对象
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
    //获取订阅者的信息,subscriberInfo默认为空
    findState.subscriberInfo = getSubscriberInfo(findState);  //注释2
    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  注释4
return getMethodsAndRelease(findState);
}

该方法查找该类以及其父类里的订阅方法。对于代码里的注释1,FindState的初始化

//从池中获取一个findState对象
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();
}

对于代码里的注释2,getSubscriberInfo()

private SubscriberInfo getSubscriberInfo(FindState findState) {
//我们需要的就是subscriberInfo,并没有赋值过,这里判断当然为空
if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
    SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
    if (findState.clazz == superclassInfo.getSubscriberClass()) {
        return superclassInfo;
    }
}

//这个index是使用EventBusBuilder时,可以设置的,默认为空
if (subscriberInfoIndexes != null) {
    for (SubscriberInfoIndex index : subscriberInfoIndexes) {
        SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
        if (info != null) {
            return info;
        }
    }
}
return null;
}

这里获取的subScriberInfo为空,所以会调用findUsingReflectionInSingleClass,我们看注释3

//通过反射去查找订阅方法,如该方法名所示:在单个类里面
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
    // This is faster than getMethods, especially when subscribers are fat classes like Activities
    //获取订阅者所有的方法
    //返回Method对象的一个数组,这些对象反映此Class对象的类或接口声明的所有方法,包括
    // 公共、保护、默认(包)访问所有方法,但是不包括继承
    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) {
    //获取方法的可见性修饰词,public,private等
    int modifiers = method.getModifiers();
    //获取public修饰的方法
    if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
         //获取方法参数
         Class<?>[] parameterTypes = method.getParameterTypes();
         //过滤方法参数只有一个的方法
        if (parameterTypes.length == 1) {
            Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
            //如果有SubScirbe注解,就去解析该方法
            if (subscribeAnnotation != null) {
                //获取发送的事件类型
                Class<?> eventType = parameterTypes[0];
                //检查该方法是否是有效方法
                if (findState.checkAdd(method, eventType)) {
                    //获取ThreadMode
                    ThreadMode threadMode = subscribeAnnotation.threadMode();
                    //构建一个SubscriberMethod,将该方法传递给findState的subscriberMethods
                    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");
    }
}
}

该方法就会获取到以@SusbScribe注解的方法,并且对其进行合法性检查checkAdd(),所谓合法性检查,就是检查其是否已经被添加到特定的数据集合中,进入checkAdd()进行查看

/**
 * 两层检查,第一层,通过事件类型检查,第二层,通过方法签名来检查
**/
boolean checkAdd(Method method, Class<?> eventType) {
// 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.
// Usually a subscriber doesn't have methods listening to the same event type.
//通常一个订阅者不会订阅重复的事件类型
Object existing = anyMethodByEventType.put(eventType, method);
//如果没有添加过此方法,则认为是有效方法
if (existing == null) {
    return true;
} else {
    //如果有添加过,则进行方法签名检查
    if (existing instanceof Method) {
        if (!checkAddWithMethodSignature((Method) existing, eventType)) {
            // Paranoia check
            throw new IllegalStateException();
        }
        // Put any non-Method object to "consume" the existing Method
        anyMethodByEventType.put(eventType, this);
    }
    return checkAddWithMethodSignature(method, eventType);
}
}

继续进入检查方法签名进行查看

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);
//如果methodClassOld为空,表明methodKey对应的数据不存在,即该方法没有被父类添加过,是有效方法
//如果methodClassOld不为空,是methodClass的父类,添加过该方法,考虑到子类重写,认为该方法是有效方法
//这里父类订阅的方法就无效了,被子类重写了
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
    // Only add if not already found in a sub class
    return true;
} else {
    // Revert the put, old class is further down the class hierarchy
    //保存方法签名对应的methodClass
    subscriberClassByMethodKey.put(methodKey, methodClassOld);
    return false;
}
}

至此,注释3进行完毕,我们看注释4

private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
//回收findState
findState.recycle();
synchronized (FIND_STATE_POOL) {
    for (int i = 0; i < POOL_SIZE; i++) {
        if (FIND_STATE_POOL[i] == null) {
            FIND_STATE_POOL[i] = findState;
            break;
        }
    }
}
return subscriberMethods;
}

返回查找到方法,并对FindState进行回收。 至此,第二步,查找@Subscribe()注解的方法就完成了,接下里,看第三步,绑定

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
//获取事件类型,也就是post()方法里的参数
Class<?> eventType = subscriberMethod.eventType;
//根据subscriber,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);
    }
}

//第一件事,更新订阅关系列表, 将新的订阅关系添加到列表中(方便post时调用,根据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, 将事件类型,添加进列表中(方便unregiste()时调用)
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);
    }
}
}

这里边也是三步,第一,更新subscriptionsByEventType,第二,更新typeBySubscriber,第三步,对事件进行处理,我们查看第三步

//最终都会调用该方法
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
    // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)
    // --> Strange corner case, which we don't take care of here.
    //发送至处理订阅关系的地方,暂时先不看这里,看post的地方
    postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());
}
}

该方法会唤醒订阅者去处理事件,具体逻辑,我们从post()方法里去查看。 对其源码的上半部分的分析,到此结束,以上都是我自己的理解,如有错误,不吝指教。