EventBus 原理 源码分析

EventBus项目地址为https://github.com/greenrobot/EventBus,clone到本地,主要看EventBus这个类就可以
关于EventBus的使用可以阅读这篇文章https://blog.csdn.net/Icarus_/article/details/103685194

1、注解定义

EventBus使用注解@Subscribe来标识一个注册方法,RetentionPolicy.RUNTIME表示是运行时注解,ElementType.METHOD表示可注解方法

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    //线程模型
    ThreadMode threadMode() default ThreadMode.POSTING;
    //是否是粘性事件
    boolean sticky() default false;
    //订阅事件优先级
    int priority() default 0;
}
2、EventBus初始化

EventBus发送事件,注册,反注册都会调用getDefault方法来完成实例的创建。
使用EventBus.getDefault方法获取一个EventBus对象,内部使用的是单例模式,会初始化一些重要的成员变量。单例模式的构造函数一般都是private的,而这里的构造函数是public的,这样设计的原因是EventBus在我们的程序中不仅仅只有一条总线,还有其他的EventBus总线,订阅者可以注册到不同的EventBus上,通过不同的EventBus来发送数据,不同的EventBus发送数据是相互隔离开的,订阅者只会收到注册在该线程上的数据。

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

public EventBus() {
    this(DEFAULT_BUILDER);
}

看一下EventBus类中定义的一些字段:
DEFAULT_BUILDER,是一个EventBusBuilder,EventBus是通过构造者模式build这个内部类进行对象创建的。
currentPostingThreadState,是一个ThreadLocal,可以在指定的线程中存储数据。
subscriptionsByEventType,发送event时,通过这个map找到订阅者。
typesBySubscriber,当注册和反注册事件的时候,操作这个map。
stickyEvents,维护粘性事件。
indexCount,生成的索引。
subscriberMethodFinder,对已经注解的方法的查找器。

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

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

private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
    ......
};
private final SubscriberMethodFinder subscriberMethodFinder;
private final int indexCount;

最重要的三个成员变量poster,poster就是负责线程间调度的

private final Poster mainThreadPoster;
private final BackgroundPoster backgroundPoster;
private final AsyncPoster asyncPoster;

在构造方法中初始化

mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);

1.mainThreadPoster,跟进去看一下他的初始化,发现返回的是HandlerPoster这个类,发现他是继承自Handler。handleMessage开启一个循环,从队列中获取数据,然后分发pendingPost,在判断每次分发的时间是否小于最大值,来继续下一次循环或者跳出循环。

public class HandlerPoster extends Handler implements Poster {
    //用来放即将执行的post的队列
    private final PendingPostQueue queue;
    //post事件在HandleMessage存在的最大的时间值
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    //标识handler是否运行起来了
    private boolean handlerActive;
    ......

    @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            long started = SystemClock.uptimeMillis();
            while (true) {
                //从队列中获取pendingPost,他维护着一个对象复用池
                PendingPost pendingPost = queue.poll();
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            handlerActive = false;
                            return;
                        }
                    }
                }
                //循环,在队列中获取到数据后,分发事件
                eventBus.invokeSubscriber(pendingPost);
                //每分发完事件都会对比下时间,判断时间是否小于设定的最大值
                long timeInMethod = SystemClock.uptimeMillis() - started;
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
    ......
}

2.backgroundPoster,跟进去看一下,它实现的是runnable,同样的在run方法中循环队列,发送消息。

final class BackgroundPoster implements Runnable, Poster {
    .......
    @Override
    public void run() {
        ......
        while (true) {
            PendingPost pendingPost = queue.poll(1000);
            if (pendingPost == null) {
                synchronized (this) {
                    // Check again, this time in synchronized
                    pendingPost = queue.poll();
                    if (pendingPost == null) {
                        executorRunning = false;
                        return;
                    }
                }
            }
            eventBus.invokeSubscriber(pendingPost);
        }
        ......
    }
}

3.asyncPoster,跟进去看一下,也是实现runnable,他的run方法只获取队列中的一个pendingPost进行分发。

class AsyncPoster implements Runnable, Poster {
    .......

    @Override
    public void run() {
        PendingPost pendingPost = queue.poll();
        if(pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        }
        eventBus.invokeSubscriber(pendingPost);
    }

}
3、EventBus注册
3.1 register方法

当EventBus对象创建好之后,就可以调用注册方法register来将某个类注册到这个EventBus对象上。在register方法中,通过subscriberMethodFinder的findSubscriberMethods方法找到注册到EventBus的subscriber类中所有的被@Subscribe注解的订阅事件方法,遍历找到的方法,调用subscribe方法来保存他们。

public void register(Object subscriber) {
    Class<?> subscriberClass = subscriber.getClass();
    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
    synchronized (this) {
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod);
        }
    }
}
3.2 findSubscriberMethods方法

findSubscriberMethods方法会把找到的监听方法封装成一个SubscriberMethod对象,一个监听方法就对应一个SubscriberMethod对象,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;    //方法字符串
}

findSubscriberMethods方法是如何找到一个类中所有被注解的方法的呢。EventBus会将一个类的订阅方法的列表缓存起来,如果有缓存,则会直接返回,没有再通过反射或是编译时生成的代码找到订阅方法列表

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
    //获取缓存
    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;
    }
}
3.2.1 findUsingInfo方法

看一下findUsingInfo方法,获取到findState,得到订阅者及其有关信息,通过循环来遍历,每次遍历完之后都会调用findState方法,依次找寻findState父类。最后getMethodsAndRelease方法返回和释放资源,内部主要就是清空了FindState里面的3个集合。

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    FindState findState = prepareFindState();
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
        //获取到findState它里面存储订阅者一些信息
        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中
                    findState.subscriberMethods.add(subscriberMethod);
                }
            }
        } else {
            //如果findState集合为空
            findUsingReflectionInSingleClass(findState);
        }
        findState.moveToSuperclass();
    }
    //返回和释放资源
    return getMethodsAndRelease(findState);
}

FindState是用来保存找到的注解过的方法以及他们的状态,看一下他的内部

static class FindState {
    //保存所有订阅方法
    final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
    //事件类型为key,订阅方法为value
    final Map<Class, Object> anyMethodByEventType = new HashMap<>();
    //订阅方法为key,订阅者的class对象为value
    final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
    ......
}

接着看一下prepareFindState()方法,他是从FIND_STATE_POOL对象池中找到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();
}
3.2.2 findUsingReflectionInSingleClass方法

接下来看findUsingReflectionInSingleClass方法,它通过反射获取到注册到EventBus类中的所有方法,然后遍历,过滤掉不符合的方法,保留被@Subscribe注解的方法,封装成SubscriberMethod对象保存起来。

private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
        //获取到注册到EventBus类中的所有方法
        // This is faster than getMethods, especially when subscribers are fat classes like Activities
        methods = findState.clazz.getDeclaredMethods();
    } catch (Throwable th) {
        ......
    }
    //遍历所有方法
    for (Method method : methods) {
        int modifiers = method.getModifiers();
        //如果是public,且是非静态非抽象方法
        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
            Class<?>[] parameterTypes = method.getParameterTypes();
            //是否只有1个参数,因为eventbus只允许订阅方法中的订阅事件是1个
            if (parameterTypes.length == 1) {
                //获取Subscribe注解
                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                if (subscribeAnnotation != null) {
                    //创建SubscriberMethod对象保存起来
                    Class<?> eventType = parameterTypes[0];
                    if (findState.checkAdd(method, eventType)) {
                        //获取到线程模式
                        ThreadMode threadMode = subscribeAnnotation.threadMode();
                        //将订阅方法添加到findState中
                        findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                    }
                }
            } 
            ......
        } 
        ......
    }
}

看一下里面的checkAdd方法,他是用来判断订阅的方法是否可以添加到订阅方法集合当中。在EventBus中有一个特点,一个订阅者包括他所有的父类或子类,不会有多个方法相同的全部去接受同一个事件,但是可能会出现这样一种情况:子类去订阅该事件,同时父类也会去订阅该事件,这时通过方法签名进行检查

boolean checkAdd(Method method, Class<?> eventType) {
    //2级检查:1级,仅具有事件类型的(快速)。2级具有完整签名的。
    //通常订阅者没有监听相同事件类型的方法。
    //使用在FindState中定义的map,返回之前的value也就是之前的方法
    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);
    }
}
3.3 Subscribe方法

findSubscriberMethods方法返回列表List< SubscriberMethod>后,在register方法中会遍历这个列表,调用subscribe方法保存起来,在subscribe方法中,首先会创建一个订阅方法SubscriberMethod对应的Subscription对象,然后获取订阅事件对应的Subscription集合,CopyOnWriteArrayList< Subscription>,如果没有则创建,最后将新建的Subscription对象存入集合,这个集合又保存在EventBus最重要的数据结构Map<Class<?>, CopyOnWriteArrayList< Subscription>>对象subscriptionsByEventType中,EventBus的注册主要是完成subscriptionsByEventType对象数据的初始化,这个Map的key为事件类型的Class对象,value为Subscription集合。我们在EventBus中所订阅的事件都会有与之对应的订阅列表,而列表中每个Subscription都会对应一个订阅方法。

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    //获取订阅方法对应的事件
    Class<?> eventType = subscriberMethod.eventType;
    //一个订阅方法subscriberMethod对应一个Subscription
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    //获取事件对应的Subscription集合
    CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    //如果没有集合则创建,并加入subscriptionsByEventType中
    if (subscriptions == null) {
        subscriptions = new CopyOnWriteArrayList<>();
        subscriptionsByEventType.put(eventType, subscriptions);
    } else {
        if (subscriptions.contains(newSubscription)) {
            //如果newSubscription保存过则抛异常
        }
    }
    //获取CopyOnWriteArrayList<Subscription>集合的大小
    int size = subscriptions.size();
    //遍历subscriptions
    for (int i = 0; i <= size; i++) {
        //根据优先级将新建的newSubscription加入集合
        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.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);
        }
    }
}

总结一下subscribe
1.首先判断是否注册过该事件
2.然后按照优先级插入到subscriptionsByEventType的value的list中
3.然后在添加到typesBySubscriber的value的list中
4.发布事件,checkPostStickyEventToSubscription

4、EventBus发布事件

由于注册时构建了一个事件类型对应的Subscription集合,发布时获取到该集合然后遍历,调用里面的订阅方法。
看一下post方法,先通过threadLocal获取到PostingThreadState,他就是发送事件的线程状态的封装类,内部有事件队列集合,是否正在发送事件的标志位等

public void post(Object event) {
    //通过threadLocal获取到PostingThreadState
    PostingThreadState postingState = currentPostingThreadState.get();
    //获取到事件的队列
    List<Object> eventQueue = postingState.eventQueue;
    eventQueue.add(event);
    //是否正在发送事件
    if (!postingState.isPosting) {
        //通过looper判断当前是否在主线程
        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;
        }
    }
}

post内部调用了postSingleEvent,postSingleEvent内部又调用了postSingleEventForEventType方法,他会获取到发布事件对应的Subscription集合,遍历,调用postToSubscription方法来完成订阅方法的调用。

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
    CopyOnWriteArrayList<Subscription> subscriptions;
    synchronized (this) {
        //获取到发布事件对应的Subscription集合
        subscriptions = subscriptionsByEventType.get(eventClass);
    }
    if (subscriptions != null && !subscriptions.isEmpty()) {
        for (Subscription subscription : subscriptions) {
            postingState.event = event;
            postingState.subscription = subscription;
            boolean aborted = false;
            try {
                //发布事件,调用Subscription对象对应的订阅方法
                postToSubscription(subscription, event, postingState.isMainThread);
                aborted = postingState.canceled;
            } 
            ......
        }
        return true;
    }
    return false;
}

postToSubscription里面会根据订阅方法的线程模型来完成在哪个线程执行

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {
        case POSTING:
            //posting,直接在当前线程执行
            invokeSubscriber(subscription, event);
            break;
        case MAIN:
            //mian,在主线程执行
            if (isMainThread) {
                //如果在主线程,直接执行
                invokeSubscriber(subscription, event);
            } else {
                //否则切换到主线程,内部是handler完成的
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case MAIN_ORDERED:
            //将在主线程中调用。该事件总是排队等待以后交付给订阅者,因此对post的调用将立即返回。这为事件处理提供了更严格且更一致的顺序
            if (mainThreadPoster != null) {
                mainThreadPoster.enqueue(subscription, event);
            } else {
                // temporary: technically not correct as poster not decoupled from subscriber
                invokeSubscriber(subscription, event);
            }
            break;
        case BACKGROUND:
            if (isMainThread) {
                //如果当前是主线程,则在EventBus内部线程池中执行
                backgroundPoster.enqueue(subscription, event);
            } else {
                //不在主线程直接调用
                invokeSubscriber(subscription, event);
            }
            break;
        case ASYNC:
            //在EventBus内部线程池中执行
            asyncPoster.enqueue(subscription, event);
            break;
        default:
            throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
    }
}
5、EventBus的反注册

注册是给Map<Class<?>, CopyOnWriteArrayList>对象subscriptionsByEventType中添加Subscription集合,那么反注册就是清除掉订阅者subscriber的Subscription

public synchronized void unregister(Object subscriber) {
    //获取订阅者订阅事件类型的集合
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        //遍历
        for (Class<?> eventType : subscribedTypes) {
            //通过事件类型和订阅者找到对应的Subscription并清除
            unsubscribeByEventType(subscriber, eventType);
        }
        //移除订阅者
        typesBySubscriber.remove(subscriber);
    } else {
        logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}

typesBySubscriber是Map<Object, List<Class<?>>>类型的集合,key是订阅者,value是订阅者订阅事件类型集合。他的数据添加是在注册时完成的,反注册时通过他获取订阅者订阅事件类型集合,然后遍历集合,调用unsubscribeByEventType。

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--;
            }
        }
    }
}
6、EventBus3.0的索引
6.1、索引的创建

EventBus有一个注解处理器模块EventBusAnnotationProcessor,此模块下只有一个类EventBusAnnotationProcessor

@SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe")
@SupportedOptions(value = {"eventBusIndex", "verbose"})
public class EventBusAnnotationProcessor extends AbstractProcessor {
    ......
}

@SupportedAnnotationType指定处理的注解为@Subscribe,@SupportedOptions指定处理注解的参数,eventBusIndex和verbose,这两个参数是在build.gradle配置的(配置见eventBus的使用)。

eventBusIndex指定将要生成的EventBus的索引类,verbose是布尔值,编译时是否打印log。注解处理器的配置文件在模块下的META-INF/services/javax.annotation.processing.Processor里,内容为

org.greenrobot.eventbus.annotationprocessor.EventBusAnnotationProcessor

接下来看EventBusAnnotationProcessor的process方法是如何处理注解来生成索引文件的

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
    //信使,用来编译时打印log
    Messager messager = processingEnv.getMessager();
    try {
        //获取参数eventBusIndex
        String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX);
        ......
        //获取参数verbose
        verbose = Boolean.parseBoolean(processingEnv.getOptions().get(OPTION_VERBOSE));
        int lastPeriod = index.lastIndexOf('.');
        //获取生成索引文件的包名
        String indexPackage = lastPeriod != -1 ? index.substring(0, lastPeriod) : null;
        ......
        //收集所有订阅者信息
        collectSubscribers(annotations, env, messager);
        //检查订阅者,如果不是public的类里面或者里面的事件也不是public则忽略
        checkForSubscribersToSkip(messager, indexPackage);
        if (!methodsByClass.isEmpty()) {
            //创建索引文件
            createInfoIndexFile(index);
        } else {
            ......
        }
        writerRoundDone = true;
    } 
    ......
    return true;
}

在process方法中,先获取eventBusIndex和verbose参数,然后调用collectSubscribers方法收集所有订阅者信息,检查订阅者,如果不是public的类里面或者里面的事件也不是public则忽略,最后调用createInfoIndexFile生成索引文件。
collectSubscribers收集收集所有订阅者和他内部所有的订阅方法,然后保存在一个ListMap集合methodsByClass中,由于EventBusAnnotationProcessor只处理@Subscribe注解,所以collectSubscribers第一个参数annotations集合中只有一个@Subscribe对应的TypeElement

private void collectSubscribers(Set<? extends TypeElement> annotations, RoundEnvironment env, Messager messager) {
    //遍历所有注解类型元素,这里只有注解@Subscribe对应的类型元素
    for (TypeElement annotation : annotations) {
        //获取所有被@Subscribe注解的元素,也就是订阅方法对应的元素
        Set<? extends Element> elements = env.getElementsAnnotatedWith(annotation);
        //遍历所有方法对应的elements
        for (Element element : elements) {
            if (element instanceof ExecutableElement) {
                ExecutableElement method = (ExecutableElement) element;
                if (checkHasNoErrors(method, messager)) {
                    //获取订阅方法外部元素,就是所在类的元素类型,如MainActivity
                    TypeElement classElement = (TypeElement) method.getEnclosingElement();
                    methodsByClass.putElement(classElement, method);
                }
            } else {
                messager.printMessage(Diagnostic.Kind.ERROR, "@Subscribe is only valid for methods", element);
            }
        }
    }
}

通过collectSubscribers收集到所有的订阅者信息后,就调用createInfoIndexFile创建索引类,使用的是JDK的JavaFileObject来生成Java文件。

6.2、索引的使用

生成索引文件后,就可以使用这个索引文件初始化EventBus实例,因为所有的订阅方法都在索引文件保存起来了,就不需要通过遍历和反射注解来解析订阅方法了。

EventBusBuilder方法创建一个EventBusBuilder对象,然后通过addIndex方法将生成的的索引类加入集合,最后调用InstallDefaultEventBus方法创建EventBus对象。在构造方法中使用subscriberInfoIndexes初始化SubscriberMethodFinder对象。
接下来在注册过程中使用SubscriberMethodFinder查找订阅方法时,会直接使用索引类获取订阅方法。

EventBus(EventBusBuilder builder) {
    ......
    //使用subscriberInfoIndexes初始化subscriberMethodFinder
    subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
            builder.strictMethodVerification, builder.ignoreGeneratedIndex);
    ......
}

默认使用findUsingInfo方法查找所有的订阅方法,会调用getSubscriberInfo()通过查找索引文件的方式来获取订阅者所对应的订阅者信息SubscriberInfo对象,如果没有开启索引加上,则会退化为反射查找。

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
    //准备一个查找状态的对象,用来跟踪订阅方法查找的过程
    FindState findState = prepareFindState();
    //设置findState的订阅者类
    findState.initForSubscriber(subscriberClass);
    while (findState.clazz != null) {
        //通过索引获取subscriberInfo,该对象中包含所有的订阅方法
        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);
}

看getSubscriberInfo()方法

private SubscriberInfo getSubscriberInfo(FindState findState) {
    ......
    if (subscriberInfoIndexes != null) {
        //遍历所有索引文件
        for (SubscriberInfoIndex index : subscriberInfoIndexes) {
            //获取订阅者信息
            SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
            if (info != null) {
                return info;
            }
        }
    }
    return null;
}

然后就可以通过这个订阅者信息对象获取其中的SubscriberMethod数组,完成订阅方法的查找

@Override
public synchronized SubscriberMethod[] getSubscriberMethods() {
    int length = methodInfos.length;
    SubscriberMethod[] methods = new SubscriberMethod[length];
    for (int i = 0; i < length; i++) {
        SubscriberMethodInfo info = methodInfos[i];
        methods[i] = createSubscriberMethod(info.methodName, info.eventType, info.threadMode,
                info.priority, info.sticky);
    }
    return methods;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值