EventBus简单使用和源码解析

来源:互联网 发布:淘宝野马软件视频 编辑:程序博客网 时间:2024/05/21 07:12

EventBus源码分析文档

此讲解基于EventBus3.0源码Author: laoXu


EventBus 目录结构如下:

EventBus最基本的使用方法及步骤

  • 1、首先先注册一个EventBus,注册方法如下:
    // 注册EventBus        EventBus.getDefault().register(this);
  • 2、在销毁的时候去反注册EventBus,具体代码如下:

    // 取消注册    EventBus.getDefault().unregister(this);
  • 3、创建一个订阅者,在EventBus2.0之前创建一个订阅者一般都是以方法创建,开头必须为:onEvent,EventBus3.0后则是以注解的方式去创建,注解为@Subscribe

    3.0之前的版本分别使用:1、onEvent2、onEventMainThread3、onEventBackgroundThread4、onEventAsyncpublic void onEventMainThread(TitleMessage title){titleBar.setTitle(title.title);}3.0之后版本,代码如下:         /**         * 创建一个订阅者,为:helloEvent         * @param title *--------------------------------注解参数说明------------------------------------ * threadMode 表示方法在什么线程执行   (Android更新UI只能在主线程, 所以如果需要操作UI, 需要设置ThreadMode.MainThread) * sticky     表示是否是一个粘性事件   (如果你使用postSticky发送一个事件,那么需要设置为true才能接受到事件) * priority   优先级                 (如果有多个对象同时订阅了相同的事件, 那么优先级越高,会优先被调用.) *  */    @Subscribe(threadMode = ThreadMode.MAIN)    public void helloEvent(TitleMessage title){        titleBar.setTitle(title.title);    }
  • 4、创建一个事件发送者,发送相关的消息,具体实现代码如下:

    //事件发送者发送一个消息 mes[String]:传递的消息EventBus.getDefault().post(mes);

基于EventBus最基本的使用方法及步骤进行源码分析

创建EventBus对象

  • 1、首先在使用EventBus的时候先调用的是getDefault方法,getDefault具体实现代码如下:

    /** Convenience singleton for apps using a process-wide EventBus instance. */public static EventBus getDefault() {    if (defaultInstance == null) {        synchronized (EventBus.class) {            if (defaultInstance == null) {                defaultInstance = new EventBus();            }        }    }    return defaultInstance;}

    1、getDefault使用了单例设计模式,用到了两次检测,再看看EventBus的构造方法:

    /** * Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a * central bus, consider {@link #getDefault()}. */public EventBus() {    this(DEFAULT_BUILDER);}

    2、EventBus在使用单例模式后的构造函数依然还使用了public,这样的设计是因为不仅可以只有一条总线,还可以有其他的线(bus),订阅者可以注册到不同的线上的EventBus,通过不同的EventBus实例来发送数据,不同的EventBus是相互隔离开的,订阅者都只会收到注册到该线上的事件

    3、在看看this(DEFAULT_BUILDER)方法,这里运用到了builder设计模式,在看看这些Builder中的那些参数:

    public class EventBusBuilder {    //线程池    private final static ExecutorService DEFAULT_EXECUTOR_SERVICE = Executors.newCachedThreadPool();    //当调用事件处理函数异常时是否打印异常信息    boolean logSubscriberExceptions = true;  //当没有订阅者订阅该事件时是否打印日志    boolean logNoSubscriberMessages = true;  //当调用事件处理函数异常时是否发送 SubscriberExceptionEvent 事件    boolean sendSubscriberExceptionEvent = true;  //当没有事件处理函数对事件处理时是否发送 NoSubscriberEvent 事件    boolean sendNoSubscriberEvent = true;  //是否要抛出异常,建议debug开启    boolean throwSubscriberException;  //与event有继承关系的是否需要发送    boolean eventInheritance = true;  //是否忽略生成的索引(SubscriberInfoIndex)    boolean ignoreGeneratedIndex;  //是否严格的方法名校验    boolean strictMethodVerification;  //线程池,async 和 background 的事件会用到    ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE;  //当注册的时候会进行方法名的校验(EventBus3之前方法名必须以onEvent开头),而这个列表是不参加校验的类的列表(EventBus3之后就没用这个参数了)    List<class<?>> skipMethodVerificationForClasses;  //维护着由EventBus生成的索引(SubscriberInfoIndex)   List subscriberInfoIndexes;}EventBusBuilder() {}//赋值buidler(可用户自定义的)给单例的EventBus,如果单例的EventBus不为null了,则抛出异常public EventBus installDefaultEventBus() {synchronized (EventBus.class) {        if (EventBus.defaultInstance != null) {            throw new EventBusException("Default instance already exists." +                    " It may be only set once before it's used the first time to ensure consistent behavior.");        }        EventBus.defaultInstance = build();        return EventBus.defaultInstance;    }}    public EventBus build() {        return new EventBus(this);    }}

    4、回到构造函数中去:

    EventBus(EventBusBuilder builder) {    //key为event,value为subscriber列表,这个map就是这个事件有多少的订阅者,也就是事件对应的订阅者    subscriptionsByEventType = new HashMap<>();    //key为subscriber,value为event列表,这个map就是这个订阅者有多少的事件,也就是订阅者订阅的事件列表    typesBySubscriber = new HashMap<>();    //粘性事件    stickyEvents = new ConcurrentHashMap<>();    //MainThread的poster    mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);    //Backgroud的poster    backgroundPoster = new BackgroundPoster(this);    //Async的poster    asyncPoster = new AsyncPoster(this);    indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;    //订阅者方法寻找类,默认情况下参数是(null, false, false)    subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,            builder.strictMethodVerification, builder.ignoreGeneratedIndex);    //builder中的赋值……    logSubscriberExceptions = builder.logSubscriberExceptions;    logNoSubscriberMessages = builder.logNoSubscriberMessages;    sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;    sendNoSubscriberEvent = builder.sendNoSubscriberEvent;    throwSubscriberException = builder.throwSubscriberException;    eventInheritance = builder.eventInheritance;    executorService = builder.executorService;}

    5、首先这三个HashMapsubscriptionsByEventType是以event为key,subscriber列表为value,当发送event的时候,都是去这里找对应的订阅者。typesBySubscriber是以subscriber为key,event列表为value,当register()unregister()的时候都是操作这个Map,同时对subscriberByEventType进行对应的操作。stickyEvents维护的是粘性事件,粘性事件也就是当event发送出去之后再注册粘性事件的话,该粘性事件也能接收到之前发送出去的event。

Poster

构造函数中同时还创建了3个poster,这3个poster只负责处理粘性事件。

HandlerPoster

final class HandlerPoster extends Handler {    //队列,即将执行的Post    private final PendingPostQueue queue;    //一个Post最大的在HandleMessage中的时间    private final int maxMillisInsideHandleMessage;    private final EventBus eventBus;    //handler是否运行起来了    private boolean handlerActive;    HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {        super(looper);        this.eventBus = eventBus;        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;        queue = new PendingPostQueue();    }    void enqueue(Subscription subscription, Object event) {      //PendingPost维护了一个可以复用PendingPost对象的复用池        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);        synchronized (this) {            //加入到队列中            queue.enqueue(pendingPost);            //如果handleMessage没有运行起来            if (!handlerActive) {                handlerActive = true;              //发送一个空消息,让handleMessage运行起来                if (!sendMessage(obtainMessage())) {                    throw new EventBusException("Could not send handler message");                }            }        }    }    @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的方法,分发消息                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;        }    }}
  • PendingPost的数据结构:
final class PendingPost {    Object event;//事件    Subscription subscription;//订阅    PendingPost next;//与队列的数据结构有关,指向下一个节点}

其中PendingPost维护着一个可以复用PendingPost对象的复用池,通过obtainPendingPost(Subscription, Object)方法复用,通过releasePendingPost(PendingPost)方法回收。

handleMessage() 中有一个死循环,这个死循环不停的从队列中拿数据,然后通过 EventBus.invokeSubscriber() 分发出去。每分发完一次比对一下时间,如果超过了 maxMillisInsideHandleMessage ,那么发送空 message 再次进入到 handlerMessage 中且退出本次循环。 这样做的原因是不要阻塞的UI线程(??)

BackgroundPoster

同理 BackgroundPoster ,只不过 HandlerPoster 是在 handlerMessage 中进行分发操作,而 BackgroundPoster 是在 Runnable 的 run 方法中将所有队列中的消息取出进行分发,直到取完为止。

AsyncPoster

而 AsyncPoster 虽然也是在 Runnable 的 run 方法中取出队列中的消息,但是只取一个。

准备订阅者

首先让我们来看一下EventBus最新的订阅者使用方法:注解Subscribe

@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD})public @interface Subscribe {    //线程模式,订阅者在哪个线程接收到事件    ThreadMode threadMode() default ThreadMode.POSTING;    //是否是粘性事件    boolean sticky() default false;    //优先级,默认为0    int priority() default 0;}

ThreadMode是枚举:

public enum ThreadMode {    POSTING,//post的时候是哪个线程订阅者就在哪个线程接收到事件    MAIN,//订阅者在主线程接收到事件    BACKGROUND,//订阅者在主线程接收到消息,如果post的时候不是在主线程的话,那么订阅者会在post的时候那个线程接收到事件。适合密集或者耗时少的事件。    ASYNC//订阅者会在不同的子线程中收到事件。适合操作耗时的事件。}

注册订阅者

1、注册订阅者需要调用register方法,代码如下:

// 注册EventBusEventBus.getDefault().register(this);
//--------------------------------对应的源码如下-----------------------------///** * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they * are no longer interested in receiving events. * <p/> * Subscribers have event handling methods that must be annotated by {@link Subscribe}. * The {@link Subscribe} annotation also allows configuration like {@link * ThreadMode} and priority. */public void register(Object subscriber) {    //拿到订阅者的class    Class<?> subscriberClass = subscriber.getClass();    //通过class去找到订阅方法    List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);    synchronized (this) {        for (SubscriberMethod subscriberMethod : subscriberMethods) {            subscribe(subscriber, subscriberMethod);        }    }}

在看看subscriberMethodFinder.findSubscriberMethods(subscriberClass)方法:

    List findSubscriberMethods(Class subscriberClass) {//先从METHOD_CACHE中查看是否已经有这个订阅者了        List subscriberMethods = METHOD_CACHE.get(subscriberClass);//如果有了的话直接把订阅者的方法返回        if (subscriberMethods != null) {            return subscriberMethods;        }//ignoreGeneratedIndex默认是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;        }    }

2、在使用EventBus.getDefault()时用的是默认的Builder,而使用EventBusBuilder。installDefaultItEventBus()时是设置自己可配置的Builder。这里我们先讨论默认情况下的。所以应该走到findUsingInfo(subscriberClass)方法来。

    private List findUsingInfo(Class subscriberClass) {        //1.得到一个FindState对象FindState findState = prepareFindState();        ……    }

3、在去看看prepareFindState()方法中设置的值

    //FindState复用池大小    private static final int POOL_SIZE = 4;    //FindState复用池    private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];    private FindState prepareFindState() {        synchronized (FIND_STATE_POOL) {            //遍历复用池            for (int i = 0; i < POOL_SIZE; i++) {                FindState state = FIND_STATE_POOL[i];//如果找到可复用state,将该位置清空,返回state                if (state != null) {                    FIND_STATE_POOL[i] = null;                    return state;                }            }        }        //没找到的话自己new一个        return new FindState();    }

4、prepareFindState主要是得到一个FindState,那么看一下FindState类的结构:

static class FindState {  //订阅者的方法的列表  final List subscriberMethods = new ArrayList<>();  //以EventType为key,method为value  final Map anyMethodByEventType = new HashMap<>();  //以method的名字生成一个methodKey为key,该method的类(订阅者)为value  final Map subscriberClassByMethodKey = new HashMap<>();  //构建methodKey的StringBuilder  final StringBuilder methodKeyBuilder = new StringBuilder(128);  //订阅者  Class subscriberClass;  //当前类  Class clazz;  //是否跳过父类  boolean skipSuperClasses;  //SubscriberInfo  SubscriberInfo subscriberInfo;  void initForSubscriber(Class subscriberClass) {    //clazz为当前类    this.subscriberClass = clazz = subscriberClass;    skipSuperClasses = false;    subscriberInfo = null;  }  //......}

5、继续回到findUsingInfo(subscriberClass)的执行流程:

private List findUsingInfo(Class subscriberClass) {  //1.得到一个FindState对象  FindState findState = prepareFindState();  //2.subscriberClass赋值给findState  findState.initForSubscriber(subscriberClass);  //2.findState的当前class不为null  while (findState.clazz != null) {    //2.默认情况下,getSubscriberInfo()返回的是null    findState.subscriberInfo = getSubscriberInfo(findState);    //2.那么这个if判断就跳过了    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 {//2.来到了这里      findUsingReflectionInSingleClass(findState);    }    //......  }  //......}

6、findUsingReflectionInSingleClass()方法很重要,在这里找到了哪些是订阅者订阅的方法:

//在较新的类文件,编译器可能会添加方法。那些被称为BRIDGE或SYNTHETIC方法。EventBus必须忽略两者。有修饰符没有公开,但在Java类文件中有格式定义private static final int BRIDGE = 0x40;private static final int SYNTHETIC = 0x1000;//需要忽略的修饰符private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC;private void findUsingReflectionInSingleClass(FindState findState) {  Method[] methods;  //通过反射,获取到订阅者的所有方法  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();      //判断是否是public,是否有需要忽略修饰符        if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {        //获得方法的参数         Class[] parameterTypes = method.getParameterTypes();        //EventBus只允许订阅方法后面的订阅事件是一个        if (parameterTypes.length == 1) {        //判断该方法是不是被Subcribe的注解修饰着的        Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);        if (subscribeAnnotation != null) {          //确定这是一个订阅方法          Class eventType = parameterTypes[0];                    if (findState.checkAdd(method, eventType)) {                    //通过Annotation去拿一些数据                    ThreadMode threadMode = subscribeAnnotation.threadMode();                    //添加到subscriberMethods中                    findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, ubscribeAnnotation.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");    }  }}
  • 关于BRIDGESYNTHETIC,注释中写道:
In newer class files, compilers may add methods. Those are called bridge or synthetic methods. EventBus must ignore both. There modifiers are not public but defined in the Java class file format: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1在较新的类文件,编译器可能会添加方法。那些被称为 BRIDGE 或 SYNTHETIC 方法。EventBus 必须忽略两者。有修饰符没有公开,但在 Java 类文件中有格式定义。
  • 该方法流程

1、拿到当前class的所有方法
2、过滤掉不是publicabstractstaticbridgesynthetic的方法
3、过滤出方法参数只有一个的方法
4、过滤出被Subscribe注解修饰的方法
5、将method方法和event事件添加到findState
6、将EventBus关心的method方法、event事件、threadModeprioritysticky封装成SubscriberMethod对象添加到findState.subscriberMethods列表中

7、那么先来看看findState.checkAdd(method, eventType)方法

boolean checkAdd(Method method, Class eventType) {    // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required.    // Usually a subscriber doesn't have methods listening to the same event type.    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);  }}

checkAdd分为两个层级的check,第一层级只判断event type,这样速度快一些;第二层级是多方面判断。anyMethodByEventType是一个HashMapHashMap.put()方法返回的是之前的value,如果之前没有value的话返回的是null,通常一个订阅者不会有多个方法接收同一事件,但是可能会出现子类订阅这个事件的同时父类也订阅了此事件的情况,那么 checkAddWithMenthodSignature()就派上了用场:

private boolean checkAddWithMethodSignature(Method method, Class eventType) {  methodKeyBuilder.setLength(0);  methodKeyBuilder.append(method.getName());  methodKeyBuilder.append('>').append(eventType.getName());  String methodKey = methodKeyBuilder.toString();  Class methodClass = method.getDeclaringClass();  //存储到以methodKey为Key,method的类为value的map中,返回之前methodKey存储的值  Class methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);  //如果这个值不存在或者这个值是method的类的父类的话,返回true  if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {    // Only add if not already found in a sub class    return true;  } else {    // Revert the put, old class is further down the class hierarchy    subscriberClassByMethodKey.put(methodKey, methodClassOld);    return false;  }}
  • 这里的逻辑有点混乱,但其主要思想就是不要出现一个订阅者有多个方法订阅的是同一事件

8、现在回过头来看看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;    public SubscriberMethod(Method method, Class eventType, ThreadMode threadMode, int priority, boolean sticky) {        this.method = method;        this.threadMode = threadMode;        this.eventType = eventType;        this.priority = priority;        this.sticky = sticky;    }  //......}
  • SubscriberMethod这个类将EventBus所需要的全部封装了起来

9、再回到findUsingInfo(subscriberClass):

private List findUsingInfo(Class subscriberClass) {  //1.得到一个FindState对象  FindState findState = prepareFindState();  //2.subscriberClass赋值给findState  findState.initForSubscriber(subscriberClass);  //2.findState的当前clazz不为null  while (findState.clazz != null) {  //2.默认情况下,getSubscriberInfo()返回的是null  findState.subscriberInfo = getSubscriberInfo(findState);  //2.那么这个if判断就跳过了  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 {//2.来到了这里      findUsingReflectionInSingleClass(findState);    }    //3.将当前clazz变为该类的父类,然后再进行while循环的判断    findState.moveToSuperclass();.  }  //3.将findState释放资源,放回复用池中,返回封装好的SubscriberMethod列表  return getMethodsAndRelease(findState);}
  • subscriberClass的流程

1、从复用池中或者new一个,得到findState
2、将subscriberClass复制给findState
    
1)、进入循环,判断当前clazz为不为null
    2)、不为null的话调用 findUsingReflectionInSingleClass()方法得到该类的所有的SubscriberMethod
    3)、将clazz变为clazz的父类,再次进行循环的判断
3、返回所有的SubscriberMethod

10、现在一层层的return返回到了findSubscriberMethods()方法中,将所有的SubscriberMethod存储到METHOD_CACHE当中。

METHOD_CACHE.put(subscriberClass, subscriberMethods);

10、再一层层的return返回到EventBus,register()中:

public void register(Object subscriber) {  //拿到订阅者的class  Class subscriberClass = subscriber.getClass();  //通过class去找到订阅方法  List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);  synchronized (this) {    //遍历    for (SubscriberMethod subscriberMethod : subscriberMethods) {      //订阅      subscribe(subscriber, subscriberMethod);    }  }}

EventBus.subscribe

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {      //拿到事件      Class eventType = subscriberMethod.eventType;      //封装一个Subscription出来,Subscription是将订阅者和订阅方法封装类(包括threadMode、sticky等)封装一起来了  Subscription newSubscription = new Subscription(subscriber, subscriberMethod);  //subscriptionsByEventType是以eventType为key,Subscription的ArrayList为value的HashMap,事件订阅者的保存队列,找到该事件所订阅的订阅者以及订阅者的方法、参数等      CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);  //如果没有数据,说明此事件是还没有注册过的  if (subscriptions == null) {    subscriptions = new CopyOnWriteArrayList<>();        subscriptionsByEventType.put(eventType, subscriptions);  } else {//说明此事件是已经有地方注册过了的    if (subscriptions.contains(newSubscription)) {//说明该订阅者已经注册过了的      throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event " + eventType);    }  }  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以subscriber为key,eventType的ArrayList为value的HashMap,订阅者订阅的事件列表,找到改订阅者所订阅的所有事件  List<class<?>> subscribedEvents = typesBySubscriber.get(subscriber);  if (subscribedEvents == null) {    subscribedEvents = new ArrayList<>();    typesBySubscriber.put(subscriber, subscribedEvents);  }  //添加到该订阅者的所以订阅方法列表中  subscribedEvents.add(eventType);  //如果是粘性事件  if (subscriberMethod.sticky) {    //是否支持继承关系,就是记录事件的父类(比如事件是ArrayList类型的,那么如果eventInheritance为true的话,会去找为List类型的事件。)    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).          //stickyEvents以eventType为key,event为value的ConcurrentHashMap,Sticky事件保存队列      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);    }  }}

首先判断是否有注册过,然后再按照优先级加入到subscriptionsByEventTypevalueList中,而subscriptionsByEventType是事件订阅者的保存队列,找到该事件所订阅的订阅者以及订阅者的方法、参数等,然后再添加到typesBySubscribervalueList中,而typesBySubscriber是订阅者订阅的事件列表,找到改订阅者所订阅的所有事件,最后判断一下是否是粘性事件,是的话判断事件是否需要考虑继承关系,再分发这个黏性事件。

  • 那么来看一下checkPostStickyEventToSubscription这个方法:
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {  if (stickyEvent != null) {    // If the subscriber is trying to abort the event, it will fail (event is not tracked in posting state)        // --> Strange corner case, which we don't take care of here.        postToSubscription(newSubscription, stickyEvent, Looper.getMainLooper() == Looper.myLooper());    }}
  • 再看看postToSubscription这个方法:
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {  switch (subscription.subscriberMethod.threadMode) {    case POSTING://当前线程直接调用      invokeSubscriber(subscription, event);            break;        case MAIN:            if (isMainThread) {//如果现在是UI线程,直接调用        invokeSubscriber(subscription, event);            } else {//否则加入到mainThreadPoster队列中                mainThreadPoster.enqueue(subscription, event);            }            break;    case BACKGROUND:      if (isMainThread) {//如果现在是UI线程,加入到backgroundPoster队列中                backgroundPoster.enqueue(subscription, event);            } else {//否则直接调用               invokeSubscriber(subscription, event);            }            break;      case ASYNC://无论如何都加入到asyncPoster队列中            asyncPoster.enqueue(subscription, event);            break;         default:            throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);    }}
  • 这三个Poster在上文都已经分析过了,那么来看看invokeSubscriber方法吧:
void invokeSubscriber(Subscription subscription, Object event) {  try {    subscription.subscriberMethod.method.invoke(subscription.subscriber, event);    } catch (InvocationTargetException e) {        handleSubscriberException(subscription, event, e.getCause());    } catch (IllegalAccessException e) {        throw new IllegalStateException("Unexpected exception", e);    }}
  • 最终通过反射调用。

注销订阅者

看完了注册订阅者,再来看看注销订阅者:

public synchronized void unregister(Object subscriber) {  //typesBySubscriber以subscriber为key,eventType的ArrayList为value的HashMap,订阅者订阅的事件列表,找到改订阅者所订阅的所有事件  List<class<?>> subscribedTypes = typesBySubscriber.get(subscriber);  if (subscribedTypes != null) {    for (Class eventType : subscribedTypes) {      unsubscribeByEventType(subscriber, eventType);    }      //remove掉        typesBySubscriber.remove(subscriber);     } else {    Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());     }}

再看看unsubscribeByEventType:

private void unsubscribeByEventType(Object subscriber, Class eventType) {    //subscriptionsByEventType是以eventType为key,Subscription的ArrayList为value的HashMap,事件订阅者的保存队列,找到该事件所订阅的订阅者以及订阅者的方法、参数等    List 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;                //remove掉                subscriptions.remove(i);                i--;                size--;            }        }    }}

注销的流程就是将typesBySubscribersubscriptionsByEventType中的关于该订阅者以及该订阅者中的方法、事件等remove掉。


发送事件

看完注册和注销之后,再来看看发送事件。可以从代码的任何地方发送事件,此时注册了的且匹配事件的订阅者能够接收到事件。通过EventBus.post(event)来发送事件。

public void post(Object event) {  //1.得到PostingThreadState  PostingThreadState postingState = currentPostingThreadState.get();  //......}

currentPostingThreadState是一个ThreadLocal对象,而 ThreadLocal是线程独有,不会与其他线程共享的。

private final ThreadLocal currentPostingThreadState = new ThreadLocal() {  @Override    protected PostingThreadState initialValue() {    return new PostingThreadState();    }};

其实现是返回一个PostingThreadState对象,而 PostingThreadState类的结构是:

/** For ThreadLocal, much faster to set (and get multiple values). */final static class PostingThreadState {  final List eventQueue = new ArrayList();    boolean isPosting;    boolean isMainThread;    Subscription subscription;    Object event;    boolean canceled;}

PostingThreadState封装的是当前线程的post信息,包括事件队列、是否正在分发中、是否在主线程、订阅者信息、事件实例、是否取消。那么回到post方法中:

public void post(Object event) {  //1.得到PostingThreadState  PostingThreadState postingState = currentPostingThreadState.get();  //2.获取其中的队列  List eventQueue = postingState.eventQueue;  //3.将该事件添加到队列中  eventQueue.add(event);  //4.如果postingState没有进行发送  if (!postingState.isPosting) {    //5. 判断当前线程是否是主线程    postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();        //6.将isPosting状态改为true,表明正在发送中      postingState.isPosting = true;      //7.如果取消掉了,抛出异常        if (postingState.canceled) {      throw new EventBusException("Internal error. Abort state was not reset");    }        try {              //8.循环,直至队列为空              while (!eventQueue.isEmpty()) {              //9.发送事件              postSingleEvent(eventQueue.remove(0), postingState);            }        } finally {             postingState.isPosting = false;             postingState.isMainThread = false;        }    }}

最后走到一个while循环,判断事件队列是否为空了,如果不为空,继续循环,进行postSingleEvent操作,从事件队列中取出一个事件进行发送。

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {  Class eventClass = event.getClass();    boolean subscriptionFound = false;    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) {            //发送一个NoSubscriberEvent的事件出去            post(new NoSubscriberEvent(this, event));        }    }}

lookupAllEventTypes()就是查找该事件的所有父类,返回所有的该事件的父类的class
它通过循环和递归一起用,将一个类的父类(接口)全部添加到全局静态变量eventTypes
集合中。再看一下postSingleEventForEventType方法:

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class eventClass) {  CopyOnWriteArrayList subscriptions;  synchronized (this) {    //所有订阅了event的事件集合    subscriptions = subscriptionsByEventType.get(eventClass);  }  if (subscriptions != null && !subscriptions.isEmpty()) {    for (Subscription subscription : subscriptions) {      postingState.event = event;      postingState.subscription = subscription;            boolean aborted = false;            try {              //这里调用的postToSubscription方法,上面有解析                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;}

至此, EventBus 的解析就结束了。

EventBus流程整理

订阅

1、根据订阅者来找到订阅方法和事件,封装成SubscriberMehod
2、循环每个SubscriberMethod
3、通过事件得到该事件的所有订阅者列表,再根据优先级插入到subscriptionsByEventType 的所有订阅者列表中
4、通过订阅者得到该订阅者的所有事件列表,再将事件添加到typeBySubscriber的所以事件列表中
5、是否是粘性事件
6、是的话进行分发,post此事件给当前订阅者,不是的话不管
7、结束本次循环,跳到第2步

0 0
原创粉丝点击