通过源码,分析 EventBus3.X 执行流程

EventBus 3.X 的使用,网上已经有很多优秀、详细的文章了,这里不在累赘。

这是我收藏的一篇:EventBus使用详解

本文,将结合EventBus 3.2.0版本,通过源码角度,分析EventBus 执行流程。

在EventBus的文档中 点击跳转 。对于EventBus 3.X的使用是这样的:

  1. Define events(定义事件):
public static class MessageEvent { /* Additional fields if needed */ }

2.Prepare subscribers: Declare and annotate your subscribing method, optionally specify a thread mode (准备订阅者:声明和注释您的订阅方法,可以选择指定线程模式):

@Subscribe(threadMode = ThreadMode.MAIN)  
public void onMessageEvent(MessageEvent event) {/* Do something */};

Register and unregister your subscriber. For example on Android, activities and fragments should usually register according to their life cycle(注册和注销您的订户。例如,在Android上,activities 和fragments 通常应根据其生命周期进行注册)::

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

 @Override
 public void onStop() {
     super.onStop();
     EventBus.getDefault().unregister(this);
 }
  1. Post events(发送事件):
EventBus.getDefault().post(new MessageEvent());

我们在使用过程中,基本上也的确是如此。

接下来,我们按照以上使用代码,分析EventBus的执行流程

一. EventBus.getDefault().register(this)

首先,我们从获取EventBus实例的方法getDefault()开始分析:

# EventBus.class

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

在getDefault()中使用了双重校验并加锁的单例模式来创建EventBus实例。

接着,我们看到EventBus的构造方法中做了什么:

  # EventBus.class
  
  private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

   public EventBus() {
        this(DEFAULT_BUILDER);
   }

    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的默认构造方法中又调用了它的另一个有参构造方法,将一个类型为EventBusBuilder的DEFAULT_BUILDER对象传递进去了。这里的EventBusBuilder很明显是一个EventBus的建造器,以便于EventBus能够添加自定义的参数和安装一个自定义的默认EventBus实例。

从上面的2个代码片可知: 创建EventBus对象有2种方式:
一是通过EventBus.getDefault(),
一种是传统的new EventBus() 的形式.

插一句题外话,类似与EventBusBuilder的这种写法,在Android源码中非常常见,比如Glide、Okhttp等等。这样做的好处是非常灵活的配置参数。

回到正题。

我们看一下EventBusBuilder的构造方法:

# EventBusBuilder.class

public class EventBusBuilder {

    .....
    
    EventBusBuilder() {
    }

    ....
    
}

EventBusBuilder的构造方法中什么也没有做,那我么继续查看EventBus的这个有参构造方法:

# EventBus.class
   // 以Event事件为key,以subscriptions订阅者为value,因此当发送Event时可通过该hashmap找到订阅此事件的订阅者
   private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
   // 以Subscriber订阅者为key,以types类型为value,因此当发送注册和反注册时都会操作此hashmap
   private final Map<Object, List<Class<?>>> typesBySubscriber;
   // 维护粘性事件,使用并发的hashmap保存
   private final Map<Class<?>, Object> stickyEvents;
   // 线程内部数据存储类,在指定的线程中存储数据,也只能在指定线程中获取到存储数据。
   private final ThreadLocal<PostingThreadState> currentPostingThreadState = new  ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            return new PostingThreadState();
        }
    };

   ......

  EventBus(EventBusBuilder builder) {
        // 日志打印
        logger = builder.getLogger();
        // 事件对应的 订阅者和订阅者方法集合映射的封装类 存储
        subscriptionsByEventType = new HashMap<>();
        // 注册的订阅者存储
        typesBySubscriber = new HashMap<>();
        //黏性事件储存
        stickyEvents = new ConcurrentHashMap<>();

        mainThreadSupport = builder.getMainThreadSupport();
        // Android主线程处理事件
        mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
         // Background事件发送者
        backgroundPoster = new BackgroundPoster(this);
         // 异步事件发送者
        asyncPoster = new AsyncPoster(this);

        indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
        // @Subscribe注解方法找寻器
        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;
  }

其中28-34行代码补充一下。这里新建了3个不同类型的事件发送器:

  • mainThreadPoster :主线程事件发送器,通过它的mainThreadPoster.enqueue(subscription, event)方法可以将订阅信息和对应的事件进行入队,然后通过 handler 去发送一个消息,在 handler 的 handleMessage 中去执行方法。
  • backgroundPoster:后台事件发送器,通过它的enqueue() 将方法加入到后台的一个队列,最后通过线程池去执行,注意,它在Executor的execute()方法 上添加了 synchronized关键字 并设立了控制标记flag,保证任一时间有且仅能有一个任务会被线程池执行。
  • asyncPoster:实现逻辑类似于backgroundPoster,不同于backgroundPoster的保证任一时间只且仅能有一个任务会被线程池执行的特性,asyncPoster则是异步运行的,可以同时接收多个任务。

我们接着看EventBus的regist()方法:


 #EventBus.class 

 public void register(Object subscriber) {
        // 获取订阅者的Class对象
        Class<?> subscriberClass = subscriber.getClass();
        // 通过订阅方法查找器(通过注解查找)找到订阅者里订阅方法的集合
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            //遍历集合逐一执行订阅
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }
# SubscriberMethod.class

// 订阅方法对象
public class SubscriberMethod {
    final Method method;   // 订阅的方法
    final ThreadMode threadMode;    //线程模式
    final Class<?> eventType;   // 事件类型:即我们订阅方法的唯一参数,就是事件类型;同时也是post(T)的参数。
    final int priority;   // 优先级
    final boolean sticky;   //是否是黏性事件
    /** Used for efficient comparison */
    String methodString;   // 用于有效比较,是否同一个订阅方法
}

# SubscriberMethodFinder.class

// 订阅方法查找器
class SubscriberMethodFinder {
   // 用于缓存订阅者和订阅者订阅方法集合
    private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();

    // FindState数组,缓存大小为4
    private static final int POOL_SIZE = 4;
    private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE];

    // 查找订阅方法集合
    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        //如果缓存中有subscriberClass对象对应 的订阅方法列表,则直接返回。
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

        if (ignoreGeneratedIndex) {    //ignoreGeneratedIndex默认为false
            // 使用反射查找,耗费性能
            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;
        }
    }

在第21行代码中,详细说说这个ignoreGeneratedIndex字段, 它用来判断是否使用生成的 APT 代码去优化寻找接收事件的过程,如果开启了的话,那么将会通过 subscriberInfoIndexes 来快速得到接收事件方法的相关信息。如果我们没有在项目中接入 EventBus 的 APT,那么可以将 ignoreGeneratedIndex 字段设为 false 以提高性能。这里ignoreGeneratedIndex 默认为false,所以会执行findUsingInfo()方法,后面生成 subscriberMethods 成功的话会加入到缓存中,失败的话会抛出异常。

我们看一下findUsingInfo方法:


#SubscriberMethodFinder.class

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            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();
        }
        
        // 通过findState获取方法并缓存findState
        return getMethodsAndRelease(findState);
    }

在第5行代码,调用了SubscriberMethodFinder的prepareFindState()方法创建了一个新的 FindState 类。我们先看一下prepareFindState()方法:

  #SubscriberMethodFinder.class

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

先从 FIND_STATE_POOL 即 FindState 池中取出可用的 FindState(这里的POOL_SIZE为4),如果没有的话,则通过第13行代码代码直接新建 一个新的 FindState 对象。

上面2个代码片都涉及FindState对象。我们看一下:

 
   # SubscriberMethodFinder.class
 
   // 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<>();
        final StringBuilder methodKeyBuilder = new StringBuilder(128);

        Class<?> subscriberClass;
        Class<?> clazz;
        boolean skipSuperClasses;
        SubscriberInfo subscriberInfo;
        // 初始化传入订阅类
        void initForSubscriber(Class<?> subscriberClass) {
            this.subscriberClass = clazz = subscriberClass;
            skipSuperClasses = false;
            subscriberInfo = null;
        }

        // 回收释放,已备复用
        void recycle() {
            ...
        }

        // 用来判断FindState的anyMethodByEventType map是否已经添加过以当前eventType为key的键值对,没添加过则返回true
        boolean checkAdd(Method method, Class<?> eventType) {
            ...
        }

        // 移动到父类Class
        void moveToSuperclass() {
            ...
        }

#SubscriberMethodFinder.class

// 从findState中间件中获取订阅的方法集合,并释放findState中间件,最后将findState缓存到数组中
    private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
        List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
        findState.recycle();
        synchronized (FIND_STATE_POOL) {
            //把findState存储在 FindState 池中方便下一次使用,以提高性能。
            for (int i = 0; i < POOL_SIZE; i++) {
                if (FIND_STATE_POOL[i] == null) {
                    FIND_STATE_POOL[i] = findState;
                    break;
                }
            }
        }
        return subscriberMethods;
    }

最后返回subscriberMethods。

接着,在EventBus的 register() 方法的最后会调用 subscribe 方法:


# EventBus.class

 private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
    Class<?> eventType = subscriberMethod.eventType;
    Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
    
    // 1
    CopyOnWriteArrayList<Subscription> 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();
    
    // 2
    for (int i = 0; i <= size; i++) {
        if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
            subscriptions.add(i, newSubscription);
            break;
        }
    }
    
    // 3
    List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
    if (subscribedEvents == null) {
        subscribedEvents = new ArrayList<>();
        typesBySubscriber.put(subscriber, subscribedEvents);
    }
    subscribedEvents.add(eventType);
    // 4
    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);
        }
    }
}

在注释1处,会根据 subscriberMethod的eventType,在 subscriptionsByEventType 去查找一个 CopyOnWriteArrayList ,如果没有则创建一个新的 CopyOnWriteArrayList,然后将这个 CopyOnWriteArrayList 放入 subscriptionsByEventType 中。

在注释2处,添加 newSubscription对象,它是一个 Subscription 类,里面包含着 subscriber 和 subscriberMethod 等信息,并且这里有一个优先级的判断,说明它是按照优先级添加的。优先级越高,会插到在当前 List 靠前面的位置。

在注释3处,对typesBySubscriber 进行添加,这主要是在EventBus的isRegister()方法中去使用的,目的是用来判断这个 Subscriber对象 是否已被注册过。

在注释4处,会判断是否是 sticky事件。如果是sticky事件的话,会调用 checkPostStickyEventToSubscription() 方法。黏性事件会在后面版块单独分析。

2.总结

(1)初始化EventBus对象时传入一个EventBus.Builder对象对EventBus进行初始化,其中有三个比较重要的集合和一个SubscriberMethodFinder对象。

(2)调用register方法,首先获取订阅者的Class对象,然后通过SubscriberMethodFinder对象获取订阅者中所有订阅方法集合,它先从缓存中获取,如果缓存中有,直接返回;如果缓存中没有,通过反射的方式去遍历订阅者类内部被Subscribe注解的方法,将这些参数只有一个的方法放入到集合中进行返回。

(3)按个将所有订阅者和对应事件方法进行绑定。在绑定之后会判断绑定的事件是否是粘性事件,如果是粘性事件,直接调用postToSubscription方法,将之前发送的粘性事件发送给订阅者。这就是粘性事件为什么在事件发送去之后,再注册该事件时,还能接受到此消息的。

二. 发布事件EventBus—post(event)

# EventBus.class

/** Posts the given event to the event bus. */ (将给定事件发布到事件总线)
    public void post(Object event) {
        //1
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);

        //2
        if (!postingState.isPosting) {
            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;
            }
        }
    }

注释1处,这里的currentPostingThreadState 是一个 ThreadLocal 类型的对象,里面存储了 PostingThreadState,而 PostingThreadState 中包含了一个 eventQueue 和其他一些标志位,
源码如下:


# EventBus.class

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

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

接着把传入的 event,保存到了当前线程中的一个变量 PostingThreadState 的 eventQueue 中。在注释2处,最后调用了 postSingleEvent() 方法,我们继续查看这个方法:


# EventBus.class

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
    Class<?> eventClass = event.getClass();
    boolean subscriptionFound = false;
    // 1
    if (eventInheritance) {
        // 2
        List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
        int countTypes = eventTypes.size();
        for (int h = 0; h < countTypes; h++) {
            Class<?> clazz = eventTypes.get(h);
            subscriptionFound |=
            // 3
            postSingleEventForEventType(event, postingState, clazz);
        }
    } else {
        subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
    }
    if (!subscriptionFound) {
        ...
    }
}

在注释1处,首先取出 Event 的 class 类型,接着会对 eventInheritance 标志位 判断,它默认为true,如果设为 true 的话,它会在发射事件的时候判断是否需要发射父类事件,设为 false,能够提高一些性能。

在注释2处,会调用lookupAllEventTypes() 方法,它的作用就是取出 Event 及其父类和接口的 class 列表,当然重复取的话会影响性能,所以它也做了一个 eventTypesCache 的缓存,这样就不用重复调用 getSuperclass() 方法。

在注释3处会调用postSingleEventForEventType()方法,我们看下这个方法:


# EventBus.class

 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) {
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

postSingleEventForEventType:查找所有Class对象,包括超类和接口。也应该适用于接口。


# EventBus.class

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class <?> eventClass) {
    CopyOnWriteArrayList <Subscription> subscriptions;
    synchronized(this) {
        subscriptions = subscriptionsByEventType.get(eventClass);
    }
    if (subscriptions != null && !subscriptions.isEmpty()) {
        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;
}

可以看到,这里直接根据 Event 类型从 subscriptionsByEventType 中取出对应的 subscriptions对象,最后调用了 postToSubscription() 方法。


  # EventBus.class

// 发布到订阅者,根据线程模式,进行线程切换
   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 {
                    // 如果是在子线程发送事件,则将事件入队列,通过Handler切换到主线程执行处理事件
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case MAIN_ORDERED: // 无论在哪个线程发送事件,都先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。mainThreadPoster不会为null
                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);
        }
    }



    // 用反射来执行订阅事件的方法,这样发送出去的事件就被订阅者接收并做相应处理
    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);
        }
    }

2. 总结:

(1)获取当前线程的事件队列,将要发布的事件加入到队列中。然后遍历整个队列,边移除遍历的当前事件,边发布当前事件。
(2)获取事件的Class对象,找到当前的event的所有父类和实现的接口的class集合。遍历这个集合,发布集合中的每一个事件。
(3)通过事件类型,获取订阅者和订阅者方法集合映射的封装类集合,遍历集合,将事件发送给订阅者。
(4)发送给订阅者时,根据订阅者的订阅方法注解中的线程模式,判断是否需要线程切换,若需要则切换线程进行调用,否则直接执行发布。
(5)用反射来执行订阅事件的方法,这样发送出去的事件就被订阅者接收并做相应处理。

三. EventBus.getDefault().unregister(this);

// EventBus类:

    // 从所有事件类中注销给定的订阅者
    public synchronized void unregister(Object subscriber) {
        // 获取订阅者订阅的所有事件
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            // 遍历订阅类型集合,释放之前缓存的当前类中的Subscription
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);    -----注释1
            }
            // 删除以subscriber为key的键值对,更新typesBySubscriber
            typesBySubscriber.remove(subscriber);      -----注释2
        } else {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

    // 仅更新subscriptionsByEventType,而不更新typesBySubscriber
    private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        // 得到当前参数类型对应的Subscription集合
        List<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions != null) {
            int size = subscriptions.size();
            // 遍历Subscription集合
            for (int i = 0; i < size; i++) {
                Subscription subscription = subscriptions.get(i);
                 // 如果当前subscription对象对应的注册类对象 和 要取消注册的注册类对象相同,则删除当前subscription对象
                if (subscription.subscriber == subscriber) {
                    subscription.active = false;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

注释1:unsubscribeByEventType() 方法中对 subscriptionsByEventType 移除了该 subscriber 的所有订阅信息。

注释2处,移除了注册对象和其对应的所有 Event 事件链表。

四. 黏性事件

最开始已经介绍了,发送普通事件的写法如下:

EventBus.getDefault().post(new MessageEvent());

如果是发送黏性事件,只有发送这里的代码不同。其他步骤完全一致。如果是发送黏性事件,代码如下:

EventBus.getDefault().postSticky(new MessageEvent());

EventBus的postSticky() 方法,内部源码如下所示:

public void postSticky(Object event) {
    synchronized (stickyEvents) {
        // 1
        stickyEvents.put(event.getClass(), event);
    }
    // 2
    post(event);
}

注释1处,先将该事件放入 stickyEvents 中。

注释2处使用post()发送事件。(也就是普通 EventBus.getDefault().post(new MessageEvent());执行的代码)。前面在分析普通post()时,已经分析过。

有关粘性事件的源码如下:

if (subscriberMethod.sticky) {
    Object stickyEvent = stickyEvents.get(eventType);
    if (stickyEvent != null) {
        postToSubscription(newSubscription, stickyEvent, isMainThread());
    }
}

可以看到,在这里会判断当前事件是否是 sticky 事件,如果 是,则从 stickyEvents 中拿出该事件并执行 postToSubscription() 方法。

五.总结

EventBus 的源码在Android主流三方库源码分析系列中算是比较简单的了。但是,它其中的一些思想和设计是值得借鉴的。

比如它使用 FindState 复用池来复用 FindState 对象,在各处使用了 synchronized 关键字进行代码块同步的一些优化操作。其中上面分析了这么多,EventBus最核心的逻辑就是利用了 subscriptionsByEventType 这个重要的列表,将订阅对象,即接收事件的方法存储在这个列表,发布事件的时候在列表中查询出相对应的方法并执行。

在这里插入图片描述

至此,EventBus源码分析完毕。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值