美文网首页
EventBus工作原理

EventBus工作原理

作者: 99123 | 来源:发表于2019-03-20 15:26 被阅读0次

    EventBus大家一定不陌生,组件之间传递消息只要post一下,对方就能收到,还可以任意切换线程,究竟内部是如何完成的呢?今天就一眼究竟。

    一、首先把简单的用法贴一下:

    1.注册,在需要接受消息的组件内进行注册(在组件创建的位置进行注册)

    EventBus.getDefault().register(this);

    2.编写处理消息的方法

    @Subscribe

    public void getInfo(String str){

        //发送的消息会在这里进行接受

    }

    3.发送消息在需要发送消息的组件内做如下操作

    EventBus.getDefault().post("哈罗呀");这样就可以在2步的方法内接受到我们发送的消息,就是这么神奇。

    4.最后一步别忘记在注册的组建内onDestory的时候对EventBus进行反注册

    EventBus.getDefault().unregister(this);

    二、那我们来看一下短短的几句代码背后都为我们做了些什么

    1、EventBus.getDefault(),代码点进去不出意外的单例模式

    public static EventBus getDefault() {

    if (defaultInstance == null) {

    synchronized (EventBus.class) {

    if (defaultInstance == null) {

    defaultInstance = new EventBus();

    }

    }

    }

    return defaultInstance;}

    标准的懒汉式单例模式,我们把完整的实例对象和构造函数贴出来看一下

    static volatile EventBus defaultInstance;

    public EventBus() { this(DEFAULT_BUILDER);}

    有没有发现哪里不对劲,标准的单例类的实例和构造方法不是应该都是private修饰的吗,为什么会是这样呢?其实EventBus提供了两种方式来实例化Eventbus,首先就是通过单例,我们来看下这个过程

    public EventBus() {

        this(DEFAULT_BUILDER);

    }

    private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

    单例中new EventBus的时候构建了一个EventBusBuilder并调取了重载方法

    EventBus(EventBusBuilder builder) {

    logger = builder.getLogger();

    subscriptionsByEventType = new HashMap<>();

    typesBySubscriber = new HashMap<>();

    stickyEvents = new ConcurrentHashMap<>();

    mainThreadSupport = builder.getMainThreadSupport();

    mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;

    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的方法

    public static EventBusBuilder builder() {

        return new EventBusBuilder();

    }

    看见没有返回一个EventBusBuilder,想到了什么,建造者模式,那么我们就可以通过这个EventBusBuilder去设置上面第一种方法给我们的默认属性,并最终通过EventBusBuilder.builder()构造出一个根据我们需求自定义的EventBus实例

    EventBusBuilder builder = EventBus.builder();

    builder.eventInheritance(true);

    builder.installDefaultEventBus();

    。。。。。。

    builder.sendNoSubscriberEvent(true);

    EventBus eventBus = builder.build();

    上面初始化的一些map和属性我们下面用到再说。

    2.我们来看下注册里面帮我们做了哪些事情EventBus.getDefault().register(this);

    public void register(Object subscriber) {

    Class<?> subscriberClass = subscriber.getClass();

    List<SubscriberMethod> subscriberMethods =subscriberMethodFinder.findSubscriberMethods(subscriberClass);

    synchronized (this) {

    for (SubscriberMethod subscriberMethod : subscriberMethods) {

    subscribe(subscriber, subscriberMethod);

    }

    }}

    register的时候我们把当前的Activity传进去,我们看findSubscriberMethods方法里面都做了什么

    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {

    List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);//(1)

    if (subscriberMethods != null) {

    return subscriberMethods;

    }

    if (ignoreGeneratedIndex) { //(2)

    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);

    return subscriberMethods;

    }

    }

    (1)首先去缓存中去查找,有的话直接返回,没有的话继续,我们是第一次进行注册缓存里面肯定是空的,我们继续向下看我们看(2)处的条件判断,ignoreGeneratedIndex这个是什么时候赋值的,如果大家细致的看过获取EventBus实例的时候那堆默认的build属性,就应该还有印象,我们看一下

    subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex);

    继续看下builder.ignoreGeneratedIndex中的赋值

    /** Forces the use of reflection even if there's a generated index (default: false). */public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) { this.ignoreGeneratedIndex = ignoreGeneratedIndex; return this;}

    看注释,默认这个值是false,ok我们继续返回上面的if条件判断

    那上面(2)中的条件判断应该走的是else分支findUsingInfo(subscriberClass)我们看下这个方法帮我们做了什么

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {

    FindState findState = prepareFindState();//1

    findState.initForSubscriber(subscriberClass);

    while (findState.clazz != null) {//这个在初始化FindState 将订阅类的class赋值给findState.clazz,这个地方为true

    findState.subscriberInfo = getSubscriberInfo(findState);//2

    if (findState.subscriberInfo != null) {//3

    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);

    }

    1帮我们初始化了一个FindState,我们来看下FindState类

    final List<SubscriberMethod> subscriberMethods = new ArrayList<>();

    final Map<Class, Object> anyMethodByEventType = new HashMap<>();

    final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();

    SubscriberMethod记录了订阅者类及其中的订阅方法,anyMethodByEventType 

    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的时候将findState.subscriberInfo置为null,所以直接走第二个if,看一下subscriberInfoIndexes 这个是在什么时候赋值的

    EventBus(EventBusBuilder builder) {

    subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex);

    }

    List<SubscriberInfoIndex> subscriberInfoIndexes;

    最后发现还是在构造EventBus实例的时候赋值的,但是我们会发现builder.subscriberInfoIndexes是个空值,还有对subscriberInfoIndexes进行初始化,我们回到getSubscriberInfo方法中第二个if也没能够走进去,最后只好return null,我们再回到上面的findUsingInfo方法中的3,由于getSubscriberInfo返回null,因此这个判断语句走else分支,我们看下这个方法中做了什么findUsingReflectionInSingleClass(findState);方法太长,我们把核心代码贴出来看一下

    ......

    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()));

    }

    }

    ......

    上面省略号代码是通过反射获取注册类中的所有方法,中间代码主要把@Subscribe标注的方法找出来,并获取注册的参数信息如:标注的线程、事件的优先级、是否是粘性事件等,用获取的这些信息构建一个SubscriberMethod对象并添加到findState.subscriberMethods集合中,最后findUsingInfo方法return getMethodsAndRelease(findState),这个方法主要是将我们构造的FindState放入FIND_STATE_POOL数组中,方便下次使用,ok到此findUsingInfo就全部分析完成,通过这个方法我们最终得到了List<SubscriberMethod>,我们继续往回翻到findSubscriberMethods这个方法中的(3)位置,向下走判断subscriberMethods这个是不是空,通过上面的分析,这个是不为空的,将我们的subscriberMethods和subscriberClass放到METHOD_CACHE中,下次相同的subscriberClass类register的时候就不同走下面一大堆的方法了,直接在METHOD_CACHE中查找并返回就好了,findSubscriberMethods方法的最后将我们获取的subscriberMethods返回,我们回到register方法中

    synchronized (this) {

    for (SubscriberMethod subscriberMethod : subscriberMethods) {

    subscribe(subscriber, subscriberMethod); }}

    遍历subscriberMethods并相应在走subscribe方法,我们去看看,subscribe主要做一些绑定工作,具体代码就不贴了,把其中几个关键的容器介绍下

    subscriptionsByEventType保存了相应方法的参数的.class对象为key,CopyOnWriteArrayList<Subscription> subscriptions为value的Map中

    Subscription中保存了Subscriber; subscriberMethod;两个对象

    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);

    if (subscribedEvents == null) {

    subscribedEvents = new ArrayList<>();

    typesBySubscriber.put(subscriber, subscribedEvents);

    }

    subscribedEvents.add(eventType);

    typesBySubscriber保存了订阅者为key,以及订阅者内部相应@Subscribe标注的方法的参数的class对象的集合为value的Map

    @Subscribe

    public void getInfo(String str){

    }

    subscribedEvents.add(eventType);这个eventType就是上面String的class对象

    到此我们把subscribe方法中绑定的集中关系简单介绍了下,subscribe方法中还做了粘性事件相关的绑定我们暂且先不做了解,到此我们把订阅相关的方法介绍到此结束。

    三.我们看下发送事件之后都做了哪些工作,EventBus.getDefault().post("哈罗呀");

    public void post(Object event) {

    PostingThreadState postingState = currentPostingThreadState.get();

    List<Object> eventQueue = postingState.eventQueue;//1

    eventQueue.add(event);//2

    if (!postingState.isPosting) {//3

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

    }

    }

    finally {

    postingState.isPosting = false;

    postingState.isMainThread = false;

    }

    }

    }

    currentPostingThreadState我们看到这是一个ThreadLocal,关于ThreadLocal不了解的可以了解下,这里就不多做介绍,就是一个本地线程副本变量工具类,PostingThreadState类我们上面应该也看到过,他里面记录了一些当前线程里面事件的搜集和发送状态,我们看到1处获取了PostingThreadState中维护的事件队列,2将要发送的事件放入到队列中,往下走到3的if判断中,我们看到postingState.isPosting默认是false,走进判断分支中,我们直接看关键的第四步,这里是一个while循环,会吧队列中的事件发送的同时,将事件从队列中删除,我们看下postSingleEvent方法

    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {

    Class<?> eventClass = event.getClass();

    boolean subscriptionFound = false;

    if (eventInheritance) {//1

    List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);//2

    int countTypes = eventTypes.size();

    for (int h = 0; h < countTypes; h++) {//3

    Class<?> clazz = eventTypes.get(h);

    subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);

    }

    } else {

    subscriptionFound = postSingleEventForEventType(event, postingState, eventClass); }

    if (!subscriptionFound) {

    if (logNoSubscriberMessages) {

    logger.log(Level.FINE, "No subscribers registered for event " + eventClass); }

    if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) {

    post(new NoSubscriberEvent(this, event));

    }

    }

    }

    postSingleEvent方法中的1,eventInheritance这个值是在构建EventBus的时候初始化的boolean eventInheritance =true;默认为true,走到2lookupAllEventTypes方法中,代码补贴了,直接看一下注释

    Looks up all Class objects including super classes and interfaces. Should also work for interfaces.

    查找所有类对象,包括超类和接口

    就是讲发送事件的class对象,包括父类和接口的所有的,放入集合中并返回List<Class<?>> eventTypes,还做了一件事情,放入到eventTypesCache中,下次同样的就直接返回。ok我们回到postSingleEvent方法的3处继续,这里for循环遍历我们刚才获取的eventTypes集合,并调用postSingleEventForEventType方法,我们看一下postSingleEventForEventType方法中的关键方法

    postToSubscription(subscription, event, postingState.isMainThread);

    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 {

    // temporary: technically not correct as poster not decoupled from subscriber 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("Unknown thread mode: " + subscription.subscriberMethod.threadMode);

    }

    }

    我们看到postToSubscription方法中会根据我们设置的不同的线程进行不同的处理,其实做的操作都是反射调用注册者内响应的方法,我们随便看一下方法具体的实现

    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);

    }

    }

    invokeSubscriber方法中的1处,这个我们应该不陌生就是反射调用方法把我们发送的事件event传过去,到此Eventbus基本流程就全部介绍完毕,如有不正确的地方欢迎评论区讨论。

    相关文章

      网友评论

          本文标题:EventBus工作原理

          本文链接:https://www.haomeiwen.com/subject/evxouqtx.html