EventBus源码解析

eventbus源码详解
概念:android中主线程实际上就是ActivityThread这个类。
在这里插入图片描述
EventBus处理流程如上:
发布器,将event通过post方法发送到EventBus总线当中,根据event事件的类型,匹配订阅者。而Subscriber则必须有一个register(注册)去注册这个event,对应unregister。
EventBus可以在任意位置发送事件。
EventBus用法
1.定义事件Event
2.准备订阅者
3.订阅者同时需要在总线上注册和注销自己
4.发送事件

源码分析

首先从EventBus.getDefault().post();的getDefault进去,毕竟先发,所以还是要一步一步来。

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

可以看出,上面是一个DCL的单例模式,没啥说的。(真的没有嘛,单例一共六种,还记得几个?懒汉,饿汉,饿汉安全,DCL,静态内部类,枚举,实际上会最后两种就够了…)
既然没啥看的,那么我们就看其构造函数

 public EventBus() {
        this(DEFAULT_BUILDER);
    }

单例模式,构造函数一般是private(这个没毛病,但这里却是public!)----》
EventBus在我们的进程中,不仅仅只有一条总线,这样注册者就可以注册到不同的EventBus总线上来发送数据(可以在一个类中发送多个事件),发送者在不同的总线上发送。

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

EventBus构造函数中传入的DEFAULT_BUILDER,实际上就是这个EventBusBuider,同时我们也可以知道,EventBus的构建是通过EventBusBuilder这个类实现的。

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

ThrealLocal,线程内部数据存储类,通过它可以在指定的线程中存储数据,存储完后只能在指定的线程中获得指定数据,其他线程无法获取到该数据。

 EventBus(EventBusBuilder builder) {
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        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中有三个最重要的参数(Poster):

mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
backgroundPoster = new BackgroundPoster(this);
asyncPoster = new AsyncPoster(this);

这三个是负责线程间调度的。

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

就是为了找@Subscribe,订阅者,

eventInheritance = builder.eventInheritance;

对于继承的类是否也需要发送event。

@Subscribe

@Documented
@Retention(RetentionPolicy.RUNTIME)//可以在运行时有效
@Target({ElementType.METHOD}) //描述方法
public @interface Subscribe {
    ThreadMode threadMode() default ThreadMode.POSTING;//指定了线程模式

    /**
     * If true, delivers the most recent sticky event (posted with
     * {@link EventBus#postSticky(Object)}) to this subscriber (if event available).
     */
    boolean sticky() default false;

    /** Subscriber priority to influence the order of event delivery.
     * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before
     * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of
     * delivery among subscribers with different {@link ThreadMode}s! */
    int priority() default 0;
}
ThreadMode threadMode() default ThreadMode.POSTING

这里着重看一下threadMode,就是@Subscribe后面的模式:

public enum ThreadMode {
    POSTING,
    MAIN,
    BACKGROUND,
    ASYNC
}

点进去后,可以看到这是个枚举类,实际上,都有注释的,我给删掉了,这里大致说一下四种模式的区别:
POSTING:默认的线程模式,调用完post会直接在调用线程中执行订阅者里的方法。
MAIN:在主线程中执行订阅者的方法。
BACKGROUND:在后台线程中执行订阅者的方法,后台进程只有一个 ,如果是子线程中调用那么会直接在子线程中处理,如果发送者是在主线程中,那么会依次排队处理多个方法(可能有多个post)。
ASYNC:无论是否在主线程中,都会在子线程中进行处理,相互独立,互不影响。

 boolean sticky() default false;

这一句就是判断是否是粘性事件
黏性事件
事件消费者在事件发布之后才注册的也能接收到该事件(Sticky Broadcast)
在广播发送结束后会保存刚刚发送的广播
(比如Activity栈里为A,B,我们给C发广播,C实际上还没有注册广播,等进了C之后如果不用粘性广播,实际上就收不到了,而如果用了sticky,那进入C注册后,还是能接收到广播的)

int priority() default 0;

优先级。

在使用Subscribe注解时可以根据需求threadMode、sticky、priority三个属性

注册事件订阅方法

register()方法:

public void register(Object subscriber) {
        // 得到当前要注册类的Class对象
        Class<?> subscriberClass = subscriber.getClass();
        // 根据Class查找当前类中订阅了事件的方法集合,即使用了Subscribe注解、有public修饰符、一个参数的方法
        // SubscriberMethod类主要封装了符合条件方法的相关信息:
        // Method对象、线程模式、事件类型、优先级、是否是粘性事等
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            // 循环遍历订阅了事件的方法集合,以完成注册
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

register()方法主要分为查找(findSubscribeMethods)和注册方法(subscribe
先从findSubscribeMethods方法入手:

List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        // METHOD_CACHE是一个ConcurrentHashMap,直接保存了subscriberClass和对应SubscriberMethod的集合,以提高注册效率,赋值重复查找。
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }
        // 由于使用了默认的EventBusBuilder,则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;
        }
    }

findSubscribeMethods(),先从缓存中查找(METHOD_CACHE),如果找到直接返回,否则去做下一步查找,然后缓存查找到的集合,通过findUsingInfo()进行下一步的查找:

private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        // 初始状态下findState.clazz就是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.clazz为subscriberClass的父类Class,即需要遍历父类
            findState.moveToSuperclass();
        }
        // 查找到的方法保存在了FindState实例的subscriberMethods集合中。
        // 使用subscriberMethods构建一个新的List<SubscriberMethod>
        // 释放掉findState
        return getMethodsAndRelease(findState);
    }

findUsingInfo()方法会在当前要注册的类以及父类中查找订阅事件的方法,这里有个FindState类,它是SubscriberMethodsFinder的内部类,用来辅助查找订阅事件的方法,具体的查找过程在findUsingReflectionInSingleClass()方法(这个才是真正查找的方法),它主要通过反射查找订阅事件的方法:

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类型,但非abstract、static等
            if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                // 获得当前方法所有参数的类型
                Class<?>[] parameterTypes = method.getParameterTypes();
                // 如果当前方法只有一个参数
                if (parameterTypes.length == 1) {
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    // 如果当前方法使用了Subscribe注解
                    if (subscribeAnnotation != null) {
                        // 得到该参数的类型
                        Class<?> eventType = parameterTypes[0];
                        // checkAdd()方法用来判断FindState的anyMethodByEventType map是否已经添加过以当前eventType为key的键值对,没添加过则返回true
                        if (findState.checkAdd(method, eventType)) {
                             // 得到Subscribe注解的threadMode属性值,即线程模式
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            // 创建一个SubscriberMethod对象,并添加到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)) {
                String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                throw new EventBusException(methodName +
                        " is a illegal @Subscribe method: must be public, non-static, and non-abstract");
            }
        }
    }

findUsingReflectionInSingleClass()里会循环遍历当前类的方法,筛选出符合条件的方法(即有Subscribe注解,public,有一个参数及事件的方法),到这一步,我们就已经找到了该类极其父类中订阅事件方法的集合了。
接着就是register()中的subscribe()方法了,即注册方法:

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        // 得到当前订阅了事件的方法的参数类型
        Class<?> eventType = subscriberMethod.eventType;
        // Subscription类保存了要注册的类对象以及当前的subscriberMethod
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        // subscriptionsByEventType是一个HashMap,保存了以eventType为key,Subscription对象集合为value的键值对
        // 先查找subscriptionsByEventType是否存在以当前eventType为key的值
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        // 如果不存在,则创建一个subscriptions,并保存到subscriptionsByEventType
        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);
            }
        }
        // 添加上边创建的newSubscription对象到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;
            }
        }
        // typesBySubscribere也是一个HashMap,保存了以当前要注册类的对象为key,注册类中订阅事件的方法的参数类型的集合为value的键值对
        // 查找是否存在对应的参数类型集合
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        // 不存在则创建一个subscribedEvents,并保存到typesBySubscriber
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        // 保存当前订阅了事件的方法的参数类型
        subscribedEvents.add(eventType);
        // 粘性事件相关的,后边具体分析
        if (subscriberMethod.sticky) {
            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<Class>).
                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);
            }
        }
    }

subscription保存要注册的类对象以及当前的subscribeMethod;
subscribe()方法主要是得到了subscriptionsByEventTypetypesBySubscriber两个HashMap。
subscriptionsByEventType保存了以eventType为key,Subscription对象为value的键值对。
typesBySubscriber也是一个HashMap,保存了以当前要注册类的对象为key注册类中订阅事件方法参数类型集合为value的键值对。
在发送事件的时候要用到subscriptionByEventType完成事件的处理;
在取消EventBus注册的时候要用到typesBySubscriber、subscriptionsByEventType,完成资源的释放。

取消注册

eventbus取消注册方法就是unregister();

public synchronized void unregister(Object subscriber) {
        // 得到当前注册类对象 对应的 订阅事件方法的参数类型 的集合
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            // 遍历参数类型集合,释放之前缓存的当前类中的Subscription
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            // 删除以subscriber为key的键值对
            typesBySubscriber.remove(subscriber);
        } else {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }

里面释放subscription的时候用到了方法unSubscribeByEventType:

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

从上面可以看出来,我们先从typesBySubscriber这个map中根据当前类,取出当前类中所有订阅事件方法参数类型的集合,然后remove掉,也就是eventType的集合,而我们上面的另一个map,即subscriptionsByEventType正是以eventType为键,subscription为value的键值对,所以我们遍历typesBySubscriber里的元素,再将subscription移除,即解绑完成。第一步解绑方法,第二步移除我们建的subscrptions。

发送事件

EventBus.getDefault().post(new ZTEvent("hello"));

发送事件我们是通过post方法来完成的:

public void post(Object event) {
        // currentPostingThreadState是一个PostingThreadState类型的ThreadLocal
        // PostingThreadState类保存了事件队列和线程模式等信息
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        // 将要发送的事件添加到事件队列
        eventQueue.add(event);
        // isPosting默认为false
        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()) {
                    // 发送单个事件
                    // eventQueue.remove(0),从事件队列移除事件
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

currentPostingThreadState是一个PostingThreadState类型的ThreadLocal(遍地都有ThreadLocal的影子)。
post()方法就是先将发送的事件保存到事件队列,然后通过循环eventQuque,将事件交给**postSingleEvent()**方法处理:

private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        // eventInheritance默认为true,表示是否向上查找事件的父类
        if (eventInheritance) {
            // 查找当前事件类型的Class,连同当前事件类型的Class保存到集合
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            // 遍历Class集合,继续处理事件
            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()方法的核心就是遍历发送的事件类型(eventType)所对应的Subscription集合,也就是我们注册时(subscribe)时生成的subscriptionsByEventType这个键值对,然后调用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 {
                     // 如果是在子线程发送事件,则将事件入队列,通过Handler切换到主线程执行处理事件
                    // mainThreadPoster 不为空
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            // 无论在那个线程发送事件,都先将事件入队列,然后通过 Handler 切换到主线程,依次处理事件。
            // mainThreadPoster 不为空
            case MAIN_ORDERED:
                if (mainThreadPoster != null) {
                    mainThreadPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case BACKGROUND:
                // 如果在主线程发送事件,则先将事件入队列,然后通过线程池依次处理事件
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    // 如果在子线程发送事件,则直接在发送事件的线程通过反射处理事件
                    invokeSubscriber(subscription, event);
                }
                break;
            // 无论在那个线程发送事件,都将事件入队列,然后通过线程池处理。
            case ASYNC:
                asyncPoster.enqueue(subscription, event);
                break;
            default:
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
        }
    }

postToSubscription()方法就是根据订阅事件方法的threadMode、以及发送事件的线程来判断如何处理事件,处理的方法有两种:一种在相应线程直接通过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);
        }
    }

另一种就是先将事件入队列(其实就是一个List),然后作进一步处理。以mainThreadPoster.enqueue(subscription,event)为例,其中mainThreadPoster是HandlerPoster类的一个实例(eventbus的构造方法中,建了三个线程调度器,handlerpost、backgroundPoster、asyncPoster)

public class HandlerPoster extends Handler implements Poster {
    private final PendingPostQueue queue;
    private boolean handlerActive;
    ......
    public void enqueue(Subscription subscription, Object event) {
        // 用subscription和event封装一个PendingPost对象
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            // 入队列
            queue.enqueue(pendingPost);
            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 = queue.poll();
                ......
                // 进一步处理pendingPost
                eventBus.invokeSubscriber(pendingPost);
                ......
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
}

所以HandlerPoster的enqueue()方法主要就是将subscription、event对象封装成一个PendingPost对象,然后保存到队列里,之后通过Handler切换到主线程,在handleMessage()方法将中将PendingPost对象循环出队列,交给invokeSubscriber()方法进一步处理 :

void invokeSubscriber(PendingPost pendingPost) {
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        // 释放pendingPost引用的资源
        PendingPost.releasePendingPost(pendingPost);
        if (subscription.active) {
            // 用反射来执行订阅事件的方法
            invokeSubscriber(subscription, event);
        }
    }

这个方法很简单,主要就是从pendingPost中取出之前保存的event、subscription,然后用反射来执行订阅事件的方法,又回到了第一种处理方式。所以mainThreadPoster.enqueue(subscription, event)的核心就是先将事件入队列,然后通过Handler从子线程切换到主线程中去处理事件
backgroundPoster.enqueue()和asyncPoster.enqueue也类似,内部都是先将事件入队列,然后再出队列,但是会通过线程池去进一步处理事件。

黏性事件

粘性事件,我们可以先发送事件,后续再准备订阅事件的方法、注册事件。

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

postSticky()方法主要做了两件事先将事件类型和对应事件保存到stickyEvents中,方便后续使用;然后执行post(event)继续发送事件,这个post()方法就是之前发送的post()方法。所以,如果在发送粘性事件前,已经有了对应类型事件的订阅者,及时它是非粘性的,依然可以接收到发送出的粘性事件。
发送完粘性事件后,再准备订阅粘性事件的方法,并完成注册。核心的注册事件流程还是我们之前的register()方法中的subscribe()方法,前边分析subscribe()方法时,有一段没有分析的代码,就是用来处理粘性事件的 :

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        ......
        ......
        ......
        // 如果当前订阅事件的方法的Subscribe注解的sticky属性为true,即该方法可接受粘性事件
        if (subscriberMethod.sticky) {
            // 默认为true,表示是否向上查找事件的父类
            if (eventInheritance) {
                // stickyEvents就是发送粘性事件时,保存了事件类型和对应事件
                Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry<Class<?>, Object> entry : entries) {
                    Class<?> candidateEventType = entry.getKey();
                    // 如果candidateEventType是eventType的子类或
                    if (eventType.isAssignableFrom(candidateEventType)) {
                        // 获得对应的事件
                        Object stickyEvent = entry.getValue();
                        // 处理粘性事件
                        checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                    }
                }
            } else {
                Object stickyEvent = stickyEvents.get(eventType);
                checkPostStickyEventToSubscription(newSubscription, stickyEvent);
            }
        }
    }
 

可以看到,处理粘性事件就是在 EventBus 注册时,遍历stickyEvents,如果当前要注册的事件订阅方法是粘性的,并且该方法接收的事件类型和stickyEvents中某个事件类型相同或者是其父类,则取出stickyEvents中对应事件类型的具体事件,做进一步处理。继续看checkPostStickyEventToSubscription()处理方法

private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
        if (stickyEvent != null) {
            postToSubscription(newSubscription, stickyEvent, isMainThread());
        }
    }

最终还是通过postToSubscription()方法完成粘性事件的处理,这就是粘性事件的整个处理流程。

现在梳理一下整体的流程:

     EventBus单例模式为DCL,EventBus的构造方法中,通过建造者模式构建EventBus对象,其中里面实例化了三个负责线程间调度的调度器(eventbus最核心的点):HandlerPoster(handler子类)、BackgroundPoster(runnable接口)、AsyncPoster。都是通过从事件队列中取出事件分发事件(invokeSubscriber)。
    注解里表明了订阅事件的方法可以指定方法的threadMode、priority、sticky属性
    注册流程(register):分为两部分,一是查找,二是注册;首先通过findSubscriberMethods查找当前类注册的方法,先从缓存中找到如果找到就直接return,否则最终通过findUsingReflectioninSingleClass方法查找当前类中为public,带有Subscriber注解,参数为一个的方法,然后加入到METHOD_CACHE中,然后通过subscribe方法注册事件,subscribe里面主要是利用两个HashMap存储事件和类的信息:typesBySubscriber、subscriptonsByEventType;前者键是当前类,value是当前类注册方法事件的集合;后者键是当前类中注册方法事件,value是subscriptions,subscription实体类存储了当前类的信息以及注册事件方法的信息。这里如果是粘性事件就从stickyEvents中取出对应类型事件逐一执行。
    取消注册:主要是遍历typesBySubscriber,从中取出当前类中注册事件的方法, 然后遍历注册事件的方法,从subscriptionsByEventType中删除掉当前Subscription,最后从typesBySubscriber删除取消注册类对象对应的键值对。
    发送事件:postSingleEvent;将事件添加到当前线程对应的事件队列,记录当前线程类型(如果是粘性事件就保存到stickyEvents中去)。调用postToSubscription发送事件,该方法主要通过t当前线程判断如何处理事件,发送事件分为两种,一种是直接在当前线程调用invokeSubscribers通过反射处理事件;另外一种就是通过Poster将事件入队列,通过handlerPoster、backgroundPoster、asyncPoster来进行事件的处理,最终也会调用invokeSubscribers处理事件。
    发送粘性事件:第一步先将事件储存到stickyEvents中去,第二步就是通过post方法发送事件。然后在上面注册事件的subscribe方法中有一段对粘性事件的处理。最终还是通过postToSubscription处理粘性事件。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值