EventBus 原理解析

EventBus 3.0出自greenrobot,采用发布订阅模式,加入注解特性指定订阅函数运行线程。本文深入分析EventBus的工作原理,包括注册过程、事件发送流程等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

EventBus介绍:

     EventBus出自greenrobot,和之前大名鼎鼎的GreenDao出自同一家。今天我们将学习分析Event 3.0,EventBus 3.0 最新的特性就是加入了注解,通过注解的方式 告知订阅函数运行在哪个线程中,是一种发布订阅设计模式(观察者设计模式)。。

     github地址:https://github.com/greenrobot/EventBus

     官方文档:http://greenrobot.org/eventbus/documentation

EventBus的注册过程总结为:class ->找到注解方法method->map.put (class ,method)->注册完成。

在EventBus的注册过程可以发现,当传入的对象子类或者本身方法特别多的时候注册过程会很慢而且很占内存。

下面通过解析注册过程来证明这一点

EventBus使用之前首先需要能过EventBus.getDefault().register(this)注册,才能收到发送的消息

注册过程:

将当前对象通过register 传入

public void register(Object subscriber) {
//获取当前对象的class
    Class<?> subscriberClass = subscriber.getClass();
能过当时类查询当前对象里面是添加过注解的方法
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}

findSubscriberMethods方法源码如下:

判断类中是否有注册的方法,如果有赐返回,
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
    return subscriberMethods;
}
是否有强制索引/默认为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;
}

下面看一下findUsingInfo方法的实现

FindState findState = prepareFindState();
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
判断是否有子类,如果有子类将子类中的添加过注册的方法添加到Map中
    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);

findUsingReflectionInSingleClass 获取当前对象所有添加注册的方法

代码如下:

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) {//可以看出在发送消息时,一定要有一个参数。
          获取注解方法,并将方法以class,方法名缓存到MAP中
            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");
    }
}

再看注册方法

synchronized (this) { for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } }
将所有的注册方法以class为KEY,方法为Value保存到内存中,以方便后面事件调用

 

EventBus 事件发送

将object 能过EventBus.getDefault().post(object)发送出来,在EventBus内部的实现是将参数object 做为key向缓存中找到以此做key的方法,然后通过Invoke方法去执行并将参数传下(在主线程中)

原码流转如下:

post->postSingleEvent->postSingleEventForEventType->postToSubscription->invoke

当注解方法不在主线程里,发送的事件首先放在消息队列中,然后通过不停的对消息队列的读取通过invoke来调用。在注册的时候发将消息队列读消息队列的线程处于运行状态中。

 

最后eventBus 解注册将key对象从缓存中移除

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值