EventBus 源码分析

来源:互联网 发布:期货信息软件 编辑:程序博客网 时间:2024/06/06 01:39

1.EventBus

EventBus getDefault() 是一个双重校验单例模式 (DCL)

2.EventBus  register(Object subscriber)

=================================================================================

public void register(Object subscriber) {
     Class<?> subscriberClass = subscriber.getClass();
 // 用 subscriberMethodFinder 提供的方法,找到在 subscriber 这个类里面订阅的内容。
     List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
     synchronized (this) {
         for (SubscriberMethod subscriberMethod : subscriberMethods) {
             subscribe(subscriber, subscriberMethod);
         }
     }
 }
=================================================================================

 
 
一般 subscriber 为activity 或者fragment,

subscriberMethodFinder.findSubscriberMethods(subscriberClass) 方法找出Object(acy类中)event事件的方法 。

=================================================================================
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
       //从缓存中获取SubscriberMethod集合
       List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
       if (subscriberMethods != null) {
           return subscriberMethods;
       }
       //ignoreGeneratedIndex属性表示是否忽略注解器生成的MyEventBusIndex
       if (ignoreGeneratedIndex) {
        //通过反射获取subscriberMethods
           subscriberMethods = findUsingReflection(subscriberClass);
       } else {
           subscriberMethods = findUsingInfo(subscriberClass);
       }
       //在获得subscriberMethods以后,如果订阅者中不存在@Subscribe注解并且为public的订阅方法,则会抛出异常。
       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;
       }
   }
=================================================================================
其中 METHOD_CACHE用了缓存 防止重复的查找浪费性能。


private void findUsingReflectionInSingleClass(FindState findState) {
    Method[] methods;
    try {
        // This is faster than getMethods, especially when subscribers are fat classes like Activities
        //通过反射查找activity 里面带 subcriber 注解的所有方法
        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) {
                Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                if (subscribeAnnotation != null) {
                    Class<?> eventType = parameterTypes[0];
                    if (findState.checkAdd(method, eventType)) {
                        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)) {
            //注解方法 必须为public
            String methodName = method.getDeclaringClass().getName() + "." + method.getName();
            throw new EventBusException(methodName +
                    " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
        }
    }
}

在这里主要是使用了Java的反射和对注解的解析。首先通过反射来获取订阅者中所有的方法。并根据方法的类型,
参数和注解来找到订阅方法。找到订阅方法后将订阅方法相关信息保存到FindState当中。


在register()查找完 注解方法之后,调用subscribe(subscriber, subscriberMethod);
在查找完所有的订阅方法以后便开始对所有的订阅方法进行注册:

    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    //eventType 为传人的参数
        Class<?> eventType = subscriberMethod.eventType;
          //根据订阅者和订阅方法构造一个订阅事件
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
          //获取当前订阅事件中Subscription的List集合,subscriptionsByEventType = new HashMap<>();
          //eventType 为map的key, value为 CopyOnWriteArrayList
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
         //该事件对应的Subscription的List集合不存在,则重新创建并保存在subscriptionsByEventType中
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
        //订阅者已经注册则抛出EventBusException
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }
//遍历订阅事件,找到比subscriptions中订阅事件小的位置,然后插进去
        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;
            }
        }
         //通过订阅者获取该订阅者所订阅事件的集合,
         //typesBySubscriber = new HashMap<>(); key为 subscribe activity 方面 ,destroy的时候解绑
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
          //将当前的订阅事件添加到subscribedEvents中
        subscribedEvents.add(eventType);
        if (subscriberMethod.sticky) {
            if (eventInheritance) {
            //粘性事件的处理
                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);
            }
        }
    }

3 Event Post

public void post(Object event) {
     //PostingThreadState保存着事件队列和线程状态信息
      PostingThreadState postingState = currentPostingThreadState.get();
     //获取事件队列,并将当前事插入到事件队列中
      List<Object> eventQueue = postingState.eventQueue;
      eventQueue.add(event);
      if (!postingState.isPosting) {
          postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
          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;
          }
      }
  }

  首先从PostingThreadState对象中取出事件队列,然后再将当前的事件插入到事件队列当中。
  最后将队列中的事件依次交由postSingleEvent方法进行处理,并移除该事件。
 
  private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
       Class<?> eventClass = event.getClass();
       boolean subscriptionFound = false;
       //eventInheritance表示是否向上查找事件的父类,默认为true
       if (eventInheritance) {
           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) {
           if (logNoSubscriberMessages) {
               Log.d(TAG, "No subscribers registered for event " + eventClass);
           }
           if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                   eventClass != SubscriberExceptionEvent.class) {
               post(new NoSubscriberEvent(this, event));
           }
       }
   }
 
 
 eventInheritance表示是否向上查找事件的父类,它的默认值为true,可以通过在EventBusBuilder中来进行配置。
 当eventInheritance为true时,则通过lookupAllEventTypes找到所有的父类事件并存在List中,
 然后通过postSingleEventForEventType方法对事件逐一处理,
 
 private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
      CopyOnWriteArrayList<Subscription> subscriptions;
         //取出该事件对应的Subscription集合
      synchronized (this) {
      //根据事件的类,获取到类中所有注册事件 方法封装成的subscription的集合
          subscriptions = subscriptionsByEventType.get(eventClass);
      }
      if (subscriptions != null && !subscriptions.isEmpty()) {
      //将该事件的event和对应的Subscription中的信息(包扩订阅者类和订阅方法)传递给postingState
      // 遍历事件依次发送处理
          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;
  }
 
  同步取出该事件对应的Subscription集合并遍历该集合将事件event和对应Subscription传递给postingState
  并调用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 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);
    }
}

取出订阅方法的线程模式,之后根据线程模式来分别处理。举个例子,如果线程模式是MAIN,
提交事件的线程是主线程的话则通过反射,直接运行订阅的方法,如果不是主线程,我们需要mainThreadPoster
将我们的订阅事件入队列,mainThreadPoster是HandlerPoster类型的继承自Handler,
通过Handler将订阅方法切换到主线程执行

EventBus的四种ThreadMode(线程模型)

EventBus3.0有以下四种ThreadMode:

    POSTING(默认):如果使用事件处理函数指定了线程模型为POSTING,那么该事件在哪个线程发布出来的,事件处理函数就会在这个线程中运行,也就是说发布事件和接收事件在同一个线程。在线程模型为POSTING的事件处理函数中尽量避免执行耗时操作,因为它会阻塞事件的传递,甚至有可能会引起ANR。
    MAIN:
    事件的处理会在UI线程中执行。事件处理时间不能太长,长了会ANR的。
    BACKGROUND:如果事件是在UI线程中发布出来的,那么该事件处理函数就会在新的线程中运行,如果事件本来就是子线程中发布出来的,那么该事件处理函数直接在发布事件的线程中执行。在此事件处理函数中禁止进行UI更新操作。
    ASYNC:无论事件在哪个线程发布,该事件处理函数都会在新建的子线程中执行,同样,此事件处理函数中禁止进行UI更新操作。

4 订阅者取消注册
    
    //其中 subcriber 为我们register注册时候的this ,(acy)
    //反注册 可以取消acy引用,防止内存泄露
    
    public synchronized void unregister(Object subscriber) {
    List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
    if (subscribedTypes != null) {
        for (Class<?> eventType : subscribedTypes) {
            unsubscribeByEventType(subscriber, eventType);
        }
        typesBySubscriber.remove(subscriber);
    } else {
        Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
    }
}
    
 

原创粉丝点击