EventBus 源码分析

EventBus 源码分析

分析源码之前

EventBus 大神的 github,最好的老师。

一、使用

我们在平时都会运用 EventBus 去简化各个组件之间的通信,相信使用了它之后感觉是真的方便了不少,可以有效的对解耦发送方和接收方。

无论主线程中调用子线程的方法,还是子线程中调用主线程的方法,我们不必去写繁杂的 Handler ,也省去了内存泄漏等的麻烦。

首先我们简单的运用一下 EventBus。

1、添加依赖

implementation 'org.greenrobot:eventbus:3.1.1'

2、定义事件

public class Student {

    private String name;
    private String addr;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

3、准备订阅者

声明并注释您的订阅方法,可选择指定一个线程模型。

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void showSutednt(Student student) {
        Toast.makeText(this, student.toString(), Toast.LENGTH_SHORT).show();
    }

4、注册和注销订阅者

 @Override
 public void onStart() {
     super.onStart();
     EventBus.getDefault().register(this);
 }

 @Override
 public void onStop() {
     super.onStop();
     EventBus.getDefault().unregister(this);
 }

5、发布事件

Student student = new Student();
student.setAddr("北京");
student.setName("张三");
EventBus.getDefault().post(student);

二、使用须知

1、基于「发布订阅」

首先我们要明白它是基于「发布订阅」模式,通过 发布者 「Publisher」 发布事件给 「EventBus」 ,EventBus 最后把事件分发给订阅者 「Subscriber」 。<br />

<br />
image.png

2、四种线程模型

  • POSTING (默认) :事件处理函数的线程和发布事件的线程在同一个线程。也就是直接操作。
  • MAIN :事件处理函数的线程是主线程。注意不能有耗时操作。
  • BACKGROUND:事件处理函数在后台线程(只有一个后台线程)。
  • ASYNC:无论事件发布的函数在哪里,始终会新建一个新线程来运行。

分析源码

一、EventBus 的创建

EventBus#getDefault()

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

        return defaultInstance;
    }

这是最常用最经典的 DoubleCheck 单例模式来创建 EventBus 对象。

EventBus#EventBus()

 public EventBus() {
        this(DEFAULT_BUILDER);
    }

EventBus#EventBus(EventBusBuilder builder)

 EventBus(EventBusBuilder builder) {
        this.currentPostingThreadState = new ThreadLocal<EventBus.PostingThreadState>() {
            protected EventBus.PostingThreadState initialValue() {
                return new EventBus.PostingThreadState();
            }
        };
        this.logger = builder.getLogger();
        this.subscriptionsByEventType = new HashMap();
        this.typesBySubscriber = new HashMap();
        this.stickyEvents = new ConcurrentHashMap();
        this.mainThreadSupport = builder.getMainThreadSupport();
        this.mainThreadPoster = this.mainThreadSupport != null ? this.mainThreadSupport.createPoster(this) : null;
        this.backgroundPoster = new BackgroundPoster(this);
        this.asyncPoster = new AsyncPoster(this);
        this.indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        this.subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        this.logSubscriberExceptions = builder.logSubscriberExceptions;
        this.logNoSubscriberMessages = builder.logNoSubscriberMessages;
        this.sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        this.sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        this.throwSubscriberException = builder.throwSubscriberException;
        this.eventInheritance = builder.eventInheritance;
        this.executorService = builder.executorService;
    }

同样也是常用的 Builder 设计模式 来构造 EventBus 对象。

我们需要重点注意的几个参数

  • HashMap 「 subscriptionsByEventType」

  • HashMap 「typesBySubscriber」

  • ConcurrentHashMap 「stickyEvents」

  • SubscriberMethodFinder 「subscriberMethodFinder」

  • Poster 「mainThreadPoster」

  • BackgroundPoster 「 backgroundPoster」

  • AsyncPoster 「asyncPoster」

具体作用我们往下分析。

二、register

1、register

EventBusBuilder#register(Object subscriber)

    public void register(Object subscriber) {
      //首先获取 subscriber 的 Class 对象
        Class<?> subscriberClass = subscriber.getClass();
      //查找所有订阅者内部的事件方法
        List<SubscriberMethod> subscriberMethods = this.subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized(this) {
            Iterator var5 = subscriberMethods.iterator();

            while(var5.hasNext()) {
                SubscriberMethod subscriberMethod = (SubscriberMethod)var5.next();
              // 调用 subscribe 分发订阅者的事件方法
                this.subscribe(subscriber, subscriberMethod);
            }

        }
    }

从这里可以看到我们在 Activity 里进行注册的时候,实际是把 Activity 作为订阅者去注册。<br />首先获取 subscriber 的 Class 对象,然后通过 findSubscriberMethods 查询在这个订阅者类里拥有 EventBus 注解的方法,然后添加到 List<SubscriberMethod> subscriberMethods。然后依次调用 subscribe。

2、findSubscriberMethods

SubscriberMethodFinder#findSubscriberMethods

    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
     //首先看看 METHOD_CACHE 缓存中有没有,查找过的会保存在 METHOD_CACHE 缓存 
      //详解2.1 解释 SubscriberMethod
        List<SubscriberMethod> subscriberMethods = (List)METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        } else {
        //一般 ignoreGeneratedIndex 默认 false 看名字应该是通过反射来查找
            if (this.ignoreGeneratedIndex) {
                subscriberMethods = this.findUsingReflection(subscriberClass);
            } else {
                subscriberMethods = this.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;
            }
        }
    }
详解 2.1

SubscriberMethod 是 一个包装类,把方法,线程模式,事件类,优先级,是否粘性,方法名称 包装起来。方便我们使用。

public class SubscriberMethod {
    final Method method;
    final ThreadMode threadMode;
    final Class<?> eventType;
    final int priority;
    final boolean sticky;
    String methodString;
  ···省略
  }

3、findUsingReflection

SubscriberMethodFinder#findUsingReflection

    private List<SubscriberMethod> findUsingReflection(Class<?> subscriberClass) {
      // 详解 3.1  
      SubscriberMethodFinder.FindState findState = this.prepareFindState();
      // 详解 3.2
        findState.initForSubscriber(subscriberClass);
            //findState.clazz 也就是 subscriberClass
        while(findState.clazz != null) {
          //详解 3.3 把查找的信息保存在 findState 中
            this.findUsingReflectionInSingleClass(findState);
            findState.moveToSuperclass();
        }

        return this.getMethodsAndRelease(findState);
    }
详解 3.1

FindState 是查找结果类,包含 SubscriberMethod 的集合 subscriberMethods,也就是这个订阅者 class 里所有的订阅事件方法。还有 通过 事件类型 为 key 保存方法的 HashMap anyMethodByEventType,也就是把该事件类型的所有方法放到这个 HashMap 里。而 subscriberClassByMethodKey 是以方法名为 key,保存订阅者类的 HashMap。具体详细作用需要往下继续分析。

    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;
··· 省略
}

FindState 的创建运用了数组大小为4的缓存池,当 FIND_STATE_POOL[i] 不为空的时候那么就使用这个对象,然后 FIND_STATE_POOL[i] 置为 null。

 private SubscriberMethodFinder.FindState prepareFindState() {
        SubscriberMethodFinder.FindState[] var1 = FIND_STATE_POOL;
        synchronized(FIND_STATE_POOL) {
            for(int i = 0; i < 4; ++i) {
                SubscriberMethodFinder.FindState state = FIND_STATE_POOL[i];
                if (state != null) {
                    FIND_STATE_POOL[i] = null;
                    return state;
                }
            }

            return new SubscriberMethodFinder.FindState();
        }
    }
详解 3.2

对 FindState 进行 subscriberClass 等赋值和初始化

 void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = this.clazz = subscriberClass;
            this.skipSuperClasses = false;
            this.subscriberInfo = null;
        }
详解 3.3

通过反射获取 拥有 EventBus 注解的方法

    private void findUsingReflectionInSingleClass(SubscriberMethodFinder.FindState findState) {
        Method[] methods;
        try {
          //通过反射获取订阅者类里所有的方法
            methods = findState.clazz.getDeclaredMethods();
        } catch (Throwable var12) {
          //如果有权限问题 那么就获取 除了私有方法外的所有方法
            methods = findState.clazz.getMethods();
            findState.skipSuperClasses = true;
        }

        Method[] var3 = methods;
        int var4 = methods.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            Method method = var3[var5];
          //获取方法修饰符
            int modifiers = method.getModifiers();
          //修饰符是否是 public 是否可以被忽略
            if ((modifiers & 1) != 0 && (modifiers & 5192) == 0) {
              //获得方法的参数
                Class<?>[] parameterTypes = method.getParameterTypes();
              //我们只需要看 参数个数是 1 
                if (parameterTypes.length == 1) {
                  //获取注解 Subscribe
                    Subscribe subscribeAnnotation = (Subscribe)method.getAnnotation(Subscribe.class);
                   //如果有
                  if (subscribeAnnotation != null) {
                    //拿到 参数的类型 也就是 事件的类型
                        Class<?> eventType = parameterTypes[0];
                    //详解 3.4
                        if (findState.checkAdd(method, eventType)) {
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                          //把查找到的方法,事件类型,线程类型,优先级,是否粘性 放入包装类 SubscriberMethod 中。
                          //最后添加到 subscriberMethods  
                          //循环往复 最后把所有的方法以及它的包装类的所有信息都放入了查找结果类 findState 。
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                } else if (this.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 (this.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");
            }
        }

    }

详解 3.4

判断 是否可以把 这个方法 放到订阅方法集合。

  boolean checkAdd(Method method, Class<?> eventType) {
    //往 anyMethodByEventType 添加 key 类型 eventType 的,value 是 method。
    //把事件的类型和方法放到这个HashMap 中。 其实就是保证 同一个 eventType 对应一个方法
    //如果 key 没有重复则 返回 null ,如果已经有值了返回 之前的值
            Object existing = this.anyMethodByEventType.put(eventType, method);
            if (existing == null) {
                return true;
            } else {
              //如果子类和父类都去订阅该事件 那么 existing 不等于 null
                if (existing instanceof Method) {
                    if (!this.checkAddWithMethodSignature((Method)existing, eventType)) {
                        throw new IllegalStateException();
                    }

                    this.anyMethodByEventType.put(eventType, this);
                }
                                //那么我们怎么去添加 重复的呢?就需要根据方法的签名去了 详情在下面
                return this.checkAddWithMethodSignature(method, eventType);
            }
        }
        private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
            this.methodKeyBuilder.setLength(0);
            this.methodKeyBuilder.append(method.getName());
            this.methodKeyBuilder.append('>').append(eventType.getName());
            String methodKey = this.methodKeyBuilder.toString();
            Class<?> methodClass = method.getDeclaringClass();
            //subscriberClassByMethodKey HashMap 是以 方法 为 key ,methodClass 为 value。
                //一个方法对应一个 methodClass
            Class<?> methodClassOld = (Class)this.subscriberClassByMethodKey.put(methodKey, methodClass);
           //class1.isAssignableFrom(class2) 判定此 Class 对象所表示的类或接口与指定的 Class 
           //参数所表示的类或接口是否相同,或是否是其超类或超接口。
           //如果在同一个类 不同方法名 那么返回 methodClassOld== null 直接返回 true
           //如果是 同一个方法名,那么就看看这个方法所在的类是否有有亲属关系了,如果没有 那么就返回 false,不会添加
          //如果是 同一个方法名 但是是父类或者接口,那么返回 true,最后替换 anyMethodByEventType 的方法值
    
           if (methodClassOld != null && !methodClassOld.isAssignableFrom(methodClass)) {
                this.subscriberClassByMethodKey.put(methodKey, methodClassOld);
                return false;
            } else {
                return true;
            }
        }

一个 eventType 对应一个方法,一个方法对应一个 methodClass 。<br />我们具体怎么理解 anyMethodByEventType 和 subscriberClassByMethodKey 呢?<br />我们如何确定同一个 eventType 对应一个方法?anyMethodByEventType 负责存放这个键值对,如果有两个方法参数都是同一个 eventType,那么就需要用 subscriberClassByMethodKey 去保证了。看一看方法名是否相同,不相同那么就替换,如果相同那么就看是否是父类的这个方法也订阅了,如果是那么也是替换,如果不是就不会替换。

到此为止我们已经找到所有 EventBus 标注的方法了。接下来应该 subscribe(subscriber, subscriberMethod) 方法了。看看这些方法是如何被注册的。

4、subscribe

EventBus#subscribe

   private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        //获取 订阅方法的 eventType 也就是事件 class
     Class<?> eventType = subscriberMethod.eventType;
     //创建 订阅 封装类
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
       //  private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
     //这个 Map  通过 eventType 获取 所有的订阅集合
     //Subscription 详解 4.1
     CopyOnWriteArrayList<Subscription> subscriptions = (CopyOnWriteArrayList)this.subscriptionsByEventType.get(eventType);
     //如果  subscriptions 为空 那么新建 并添加 到 subscriptionsByEventType
     if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList();
            this.subscriptionsByEventType.put(eventType, subscriptions);
       //如果 里面有这个 订阅封装类 那么报错 这个类已经有这个 事件的订阅了,不能重复订阅
        } else if (subscriptions.contains(newSubscription)) {
            throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);
        }

        int size = subscriptions.size();
//按照 priority 优先级来插入集合中
        for(int i = 0; i <= size; ++i) {
            if (i == size || subscriberMethod.priority > ((Subscription)subscriptions.get(i)).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }
// 同一订阅者中 typeClass 的集合 用来判断 这个方法是否是粘性的
        List<Class<?>> subscribedEvents = (List)this.typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList();
            this.typesBySubscriber.put(subscriber, subscribedEvents);
        }

        ((List)subscribedEvents).add(eventType);
     //如果接收sticky事件,立即分发sticky事件
        if (subscriberMethod.sticky) {
          //默认情况下 event 事件允许继承,即默认情况下eventInheritance==true
            if (this.eventInheritance) {
                Set<Entry<Class<?>, Object>> entries = this.stickyEvents.entrySet();
                Iterator var9 = entries.iterator();

                while(var9.hasNext()) {
                    Entry<Class<?>, Object> entry = (Entry)var9.next();
                    Class<?> candidateEventType = (Class)entry.getKey();
                  //这里就是看 eventType 是否是 candidateEventType 类 或者 candidateEventType 的父类 、接口
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        Object stickyEvent = entry.getValue();
                        this.checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
              //如果不允许继承 那么直接就是这个 eventType class
                Object stickyEvent = this.stickyEvents.get(eventType);
              //这个最后走的是 postToSubscription 方法,我们下面会具体分析
                this.checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }

    }
详解 4.1

Subscription 封装了 subscriber 订阅者 和 subscriberMethod 订阅方法 ,以及这个订阅的是否 acitive 。

final class Subscription {
    final Object subscriber;
    final SubscriberMethod subscriberMethod;
    volatile boolean active;
   ···
    }

我们来看一下 subscriptionsByEventType 和 typesBySubscriber 又是两个 Map。

subscriptionsByEventType 是根据 tpyeClass 的查找 subscriptions,也就是根据事件类型来找 订阅集合的。这个集合有着优先级,同一事件,不同优先级的 subscription。

typesBySubscriber 是跟剧 订阅者 查找 tpyeClass,也就是根据订阅者查找其中的事件,如果有粘性的就立马分发。

到此 register 就分析完毕,说实话这样分析下来,脑袋里实在还是不懂这个流程,那我们就换一下流程图,简化一下这个流程。

image.png

三、post

我们如何把订阅者的方法和订阅事件相关联,也就是事件是如何分发到事件方法的。

首先我们需要了解 「currentPostingThreadState」 在不同线程中保存 「PostingThreadState」。

private final ThreadLocal<EventBus.PostingThreadState> currentPostingThreadState;

「PostingThreadState」 是分发线程状态,包换 事件队列 、是否正在分发、是否在主线程、是否取消了 还有订阅分装类 Subscription ,以及当前事件。记录着本线程中事件分发的状态。

    static final class PostingThreadState {
        final List<Object> eventQueue = new ArrayList();
        boolean isPosting;
        boolean isMainThread;
        Subscription subscription;
        Object event;
        boolean canceled;

        PostingThreadState() {
        }
    }
    public void post(Object event) {
        EventBus.PostingThreadState postingState = (EventBus.PostingThreadState)this.currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
      //把当前 event 添加到 eventQueue
        eventQueue.add(event);
      //如果时间没有正在分发
        if (!postingState.isPosting) {
          //对 postingState 进行赋值
            postingState.isMainThread = this.isMainThread();
            postingState.isPosting = true;
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }

            try {
              //依次 取出 event 并执行 postSingleEvent 方法。
                while(!eventQueue.isEmpty()) {
                    this.postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
              //最后对 postingState 做 默认值 处理
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }

    }

通过方法命名我们知道这是处理单个事件的方法。

1、postSingleEvent

EventBus#postSingleEvent

    private void postSingleEvent(Object event, EventBus.PostingThreadState postingState) throws Error {
     //首先获取这个类的 class 对象 
       Class<?> eventClass = event.getClass();
       //是否查找到了 订阅方法
        boolean subscriptionFound = false;
        //如果允许继承
        if (this.eventInheritance) {
        //查找该类 以及它的父类 的所有 事件类型
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
                //如果发现有匹配的事件类型??
            for(int h = 0; h < countTypes; ++h) {
                Class<?> clazz = (Class)eventTypes.get(h);
                subscriptionFound |= this.postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = this.postSingleEventForEventType(event, postingState, eventClass);
        }

        if (!subscriptionFound) {
            if (this.logNoSubscriberMessages) {
                this.logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }

            if (this.sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class && eventClass != SubscriberExceptionEvent.class) {
                this.post(new NoSubscriberEvent(this, event));
            }
        }

    }

2、postSingleEventForEventType

    private boolean postSingleEventForEventType(Object event, EventBus.PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList subscriptions;
        synchronized(this) {
          //获得该 eventClass 的所有 订阅方法
            subscriptions = (CopyOnWriteArrayList)this.subscriptionsByEventType.get(eventClass);
        }

        if (subscriptions != null && !subscriptions.isEmpty()) {
            Iterator var5 = subscriptions.iterator();

            while(var5.hasNext()) {
              //从 方法集合中取出一个 方法
                Subscription subscription = (Subscription)var5.next();
              //给 postingState 赋值 
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;

                try {
                  //这回终于要 分发成功了
                    this.postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }

                if (aborted) {
                    break;
                }
            }

            return true;
        } else {
            return false;
        }
    }

3、postToSubscription

终于有看到这个方法,在 subscrible 方法的粘性事件处理上 也是调用的这个方法,这也是我们真正分发的方法。

    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
       //首先判断 是哪种 threadMode 模式 运行
       switch(subscription.subscriberMethod.threadMode) {
        case POSTING:
        //详解 3.1
            this.invokeSubscriber(subscription, event);
            break;
        case MAIN:
         //详解 3.2
            if (isMainThread) {
                this.invokeSubscriber(subscription, event);
            } else {
                this.mainThreadPoster.enqueue(subscription, event);
            }
            break;
        case MAIN_ORDERED:
            if (this.mainThreadPoster != null) {
                this.mainThreadPoster.enqueue(subscription, event);
            } else {
                this.invokeSubscriber(subscription, event);
            }
            break;
        case BACKGROUND:
         //详解 3.3
            if (isMainThread) {
                this.backgroundPoster.enqueue(subscription, event);
            } else {
                this.invokeSubscriber(subscription, event);
            }
            break;
        case ASYNC:
        //详解 3.4
            this.asyncPoster.enqueue(subscription, event);
            break;
        default:
            throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }

    }
详解 3.1

EventBus#invokeSubscriber

    void invokeSubscriber(Subscription subscription, Object event) {
        try {
            subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
        } catch (InvocationTargetException var4) {
            this.handleSubscriberException(subscription, event, var4.getCause());
        } catch (IllegalAccessException var5) {
            throw new IllegalStateException("Unexpected exception", var5);
        }

    }

最后我们发现 invokeSubscriber 方法实际是通过 subscription 的持有的 method 的引用通过反射的方法,把 订阅者 subscriber 和 事件 event 填入,真正调用的就是 subscriber.xxx(event)。也就是 activity.xxx(event)。

饶了一大圈,其实也就是把 订阅者 和 事件的 引用保存起来,查找方法,通过反射进行调用。真是原理很简单,实现很蛋疼,不把你绕晕是不行的。

详解 3.2

如果 是在主线程中,isMainThread == true,直接 invokeSubscriber 。<br />如果 false ,那么就需要 倒一手了。其实 HandlerPoster 就是 一个 Handler , 并且它的 Lopper 是主线程的Looper 。这样就是通过 Handler ,添加到主线程了,然后执行 invokeSubscriber 。这么看切换线程原理还是 Handler。

HandlerPoster#enqueue

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized(this) {
            this.queue.enqueue(pendingPost);
            if (!this.handlerActive) {
                this.handlerActive = true;
                if (!this.sendMessage(this.obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }

        }
    }
详解 3.3

BackgroundPoster 和 主线程的 HandlerPoster 不通,它是一个 Runnable 线程。和主线程 HandlerPoster 不同的是它会把 queue 的所有 pendingPost 都去执行。

final class BackgroundPoster implements Runnable, Poster {
    private final PendingPostQueue queue;
    private final EventBus eventBus;
    private volatile boolean executorRunning;

    BackgroundPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        this.queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized(this) {
            this.queue.enqueue(pendingPost);
            if (!this.executorRunning) {
                this.executorRunning = true;
                this.eventBus.getExecutorService().execute(this);
            }

        }
    }

    public void run() {
        try {
            while(true) {
                PendingPost pendingPost = this.queue.poll(1000);
                if (pendingPost == null) {
                    synchronized(this) {
                        pendingPost = this.queue.poll();
                        if (pendingPost == null) {
                            this.executorRunning = false;
                            return;
                        }
                    }
                }

                this.eventBus.invokeSubscriber(pendingPost);
            }
        } catch (InterruptedException var9) {
            this.eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", var9);
        } finally {
            this.executorRunning = false;
        }
    }
}

详解 3.4

AsyncPoster 是一个 Runnalbe。是通过线程池产生新的线程,最后执行 invokeSubscriber 方法。和 BackgroundPoster 不同的是 一次只取一个 PendingPost。

class AsyncPoster implements Runnable, Poster {
    private final PendingPostQueue queue;
    private final EventBus eventBus;

    AsyncPoster(EventBus eventBus) {
        this.eventBus = eventBus;
        this.queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        this.queue.enqueue(pendingPost);
        this.eventBus.getExecutorService().execute(this);
    }

    public void run() {
        PendingPost pendingPost = this.queue.poll();
        if (pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        } else {
            this.eventBus.invokeSubscriber(pendingPost);
        }
    }
}
        //最后还是走的 invokeSubscriber 方法
    void invokeSubscriber(PendingPost pendingPost) {
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        PendingPost.releasePendingPost(pendingPost);
        if (subscription.active) {
            this.invokeSubscriber(subscription, event);
        }

    }

最后也要来一个流程图来总结下 post 的流程。

image.png

四、 unregister

解绑订阅者和订阅事件。

    public synchronized void unregister(Object subscriber) {
      //获取 该 订阅者 的所有 订阅事件
        List<Class<?>> subscribedTypes = (List)this.typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            Iterator var3 = subscribedTypes.iterator();

            while(var3.hasNext()) {
                Class<?> eventType = (Class)var3.next();
              //挨个 解绑 订阅者 和 订阅事件的关系
                this.unsubscribeByEventType(subscriber, eventType);
            }
                        //最后把这个 订阅者 移出 该 map
            this.typesBySubscriber.remove(subscriber);
        } else {
            this.logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }

    }
    private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
    //获取 这个订阅事件的 所有订阅者
        List<Subscription> subscriptions = (List)this.subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();

            for(int i = 0; i < size; ++i) {
                Subscription subscription = (Subscription)subscriptions.get(i);
                //判断 是否是这个订阅者 subscription 置 flase ,然后 移除 该集合
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    --i;
                    --size;
                }
            }
        }

    }

总结

一、regist

1、遍历所有 EventBus 的订阅事件。<br />2、把 封装订阅者加入 以事件类型为 key ,所有封装订阅者的集合为 values 的 Map 中。详细见注释。<br />3、把订阅事件 添加到 以 「subscriber」订阅者为 key,「subscribedEvents」订阅事件集合为 value 的 Map 中。<br />4、如果订阅了粘性事件的订阅者,那么会 粘性事件集合中获取之前的粘性事件,然后相应这些粘性事件。

注释:<br />把 「subscriber」和 「subscriberMethod」封装成 「Subscription」 封装订阅者。通过 订阅事件的 「SubscriberMethod」 获取 「eventType」,以 eventType 事件类型为 key ,封装订阅者集合(subscriptions)为 value 的 Map 「subscriptionsByEventType」。并把这个 Subscription 添加到 subscriptions 中。

二、post

1、获取该线程下的事件队列。<br />2、把要发送的事件添加到队列中。<br />3、根据订阅事件 查找所有 封装订阅者。<br />4、根据订阅方法的执行模式,在对应的线程中通过反射执行订阅者的订阅方法。

三、unregist

1、首先 获取订阅者的所有订阅事件。<br />2、遍历 订阅事件 <br />3、根据 订阅事件获取 订阅者的集合。<br />4、判断 该订阅者 是否在 封装订阅者集合 「subscriptions」中,把这个订阅者从 subscriptions 中移除。<br />5、最后 把订阅者 从「typesBySubscriber」中移除。

最后

「云开方见日,潮尽炉峰出。」——戴叔伦

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • EventBus源码分析 Android开发中我们最常用到的可以说就是EventBus了,今天我们来深入研究一下E...
    BlackFlag阅读 489评论 3 4
  • 前面对EventBus 的简单实用写了一篇,相信大家都会使用,如果使用的还不熟,或者不够6,可以花2分钟瞄一眼:h...
    gogoingmonkey阅读 309评论 0 0
  • 简介 前面我学习了如何使用EventBus,还有了解了EventBus的特性,那么接下来我们一起来学习EventB...
    eirunye阅读 452评论 0 0
  • EventBus源码分析(一) EventBus官方介绍为一个为Android系统优化的事件订阅总线,它不仅可以很...
    蕉下孤客阅读 3,945评论 4 42
  • EventBus是在Android中使用到的发布-订阅事件总线框架,基于观察者模式,将事件的发送者和接收者解耦,简...
    BrotherTree阅读 387评论 0 1