Android EventBus 源码解析

EventBus,由greenrobot组织贡献(该组织还贡献了greenDAO),一个Android事件发布/订阅轻量级框架;


进程内EventBus可以代替Android传统的Intent,Handler,Broadcast或接口函数,在Fragment,Activity,Service线程之间传递数据,执行方法;



github地址  https://github.com/greenrobot/EventBus    点击打开链接


在没有它之前,进程内通信一直都是用的广播来发送接收消息,后来用了后发现真的是太方便了,而且还是轻量级的,最近研究了下它的源码,

学习了下大神牛逼的架构和思维,确实很厉害,为啥我没想到呢。


怎么使用的就不做介绍了,相信大家都会用,下面直接进入正文


先看下源码结构,如图:



代码量其实不是很多,很多类里面就只有一点代码,前面3个文件目录都是一些辅助工具类,不是核心,有空可以去学习下,

这里只解析主干逻辑。



平时我们主要用这几个方法:注册订阅者,注销订阅者,定义订阅方法,post事件,所以就从这几个方面开始解析


首先我们知道EventBus用的是单例模式,整个进程中只会有一个EventBus的实例


    static volatile EventBus defaultInstance;

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


这里加上同步,防止多线程调用getDefault()时出现几个实例



接下来看下定义订阅方法


    @Subscribe(threadMode = ThreadMode.MAIN)
    public void refreshUI(RefreshBagEvent event) {
        
    }

    @Subscribe
    public void loadData(DataChangeEvent event) {

    }

平时就是这么定义的订阅方法,为啥要这么写呢,我们先看下这个注解@Subscribe

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Subscribe {
    /**
     * 指定订阅方法所在线程
     * @return
     */
    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;

}

这个定义的注解包含了3个方法,都有默认值,订阅方法所在线程、是否开启粘性事件模式、优先级


为啥要定义这么一个注解呢?


问题先放这,后面揭晓,接下来看下注册订阅者方法register()

    /**
     * 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<?> subscriberClass = subscriber.getClass();
        // 获取订阅者订阅的方法
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        // 加上同步block,可能同时有多处都在注册
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }

当前订阅者register传入进来,拿到它的Class对象,根据这个Class对象获取register的订阅方法,看下这些订阅方法如何被获取的

    private static final Map<Class<?>, List<SubscriberMethod>> METHOD_CACHE = new ConcurrentHashMap<>();

    List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
        List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
        if (subscriberMethods != null) {
            return subscriberMethods;
        }

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

可以看到调用了findUsingReflection()或者findUsingInfo(),ignoreGeneratedIndex默认是false,那么就会直接调用 findUsingReflection(),继续往下看

    private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
        FindState findState = prepareFindState();
        findState.initForSubscriber(subscriberClass);
        while (findState.clazz != null) {
            findState.subscriberInfo = getSubscriberInfo(findState);
            // 这里应该是从缓存中获取订阅的方法,不过看源码findState.subscriberInfo永远都是null,所以进不去
            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 {
                // 利用反射获取订阅方法储存在findState里面
                findUsingReflectionInSingleClass(findState);
            }
            findState.moveToSuperclass();
        }
        // 从findState中获取订阅方法
        return getMethodsAndRelease(findState);
    }

    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();
                // 如果只有一个参数
                if (parameterTypes.length == 1) {
                    // 获取方法中Subscribe注解
                    Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
                    // 方法中Subscribe注解不为null
                    if (subscribeAnnotation != null) {
                        Class<?> eventType = parameterTypes[0];
                        // 检查findState是否添加过这个订阅方法
                        if (findState.checkAdd(method, eventType)) {
                            ThreadMode threadMode = subscribeAnnotation.threadMode();
                            findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
                                    subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
                        }
                    }
                } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                    // 抛出异常,订阅的方法必须只有一个参数
                    String methodName = method.getDeclaringClass().getName() + "." + method.getName();
                    throw new EventBusException("@Subscribe method " + methodName +
                            "must have exactly 1 parameter but has " + parameterTypes.length);
                }
            } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
                // 抛出异常,订阅的方法必须是public,不带static、abstract的
                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()反射获取订阅方法,看到这知道为啥要用注解@Subcribe了吧,因为一个类那么多方法,怎么知道哪些方法是订阅方法呢,就是用这个注解作为标识

    private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
        List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
        // 回收findState的数据
        findState.recycle();
        synchronized (FIND_STATE_POOL) {
            for (int i = 0; i < POOL_SIZE; i++) {
                if (FIND_STATE_POOL[i] == null) {
                    FIND_STATE_POOL[i] = findState;
                    break;
                }
            }
        }
        return subscriberMethods;
    }


到这里,这个订阅者的方法都以List的形式返回了,接着回到register()


    public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass();
        // 获取订阅者订阅的方法
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
        // 加上同步block,可能同时有多处都在注册
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }


接下来就是开始循环把这些订阅方法一个一个的注册了,看下subscribe()

    // Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        // 获取事件.class对象
        Class<?> eventType = subscriberMethod.eventType;
        // 创建一个含有订阅者和订阅方法的订阅实体
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        // 根据事件类型获取订阅实体集合,CopyOnWriteArrayList是线程安全的
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
        if (subscriptions == null) {
            // 如果subscriptionsByEventType还没有事件.class对象eventType相关的订阅实体集合,就new 一个
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            // 如果subscriptionsByEventType有eventType相关的订阅实体集合,且包含newSubscription,抛出异常已经注册过了
            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;
            }
        }

        // typesBySubscriber用于判断是否注册过某个订阅者
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);

        // sticky默认false
        if (subscriberMethod.sticky) {
            // eventInheritance 默认为true
            // 如果eventType代表的类或者接口是candidateEventType代表的类或者接口或者父类父接口,也要post事件
            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);
            }
        }
    }

这个方法还挺长的,解析我都写在代码里面了,逻辑还是挺复杂的

    /**
     * 储存事件及父类父接口Class对象;
     * key:事件Class对象,value:事件及父类父接口Class对象
     */
    private static final Map<Class<?>, List<Class<?>>> eventTypesCache = new HashMap<>();

    /**
     * 储存事件及对应方法;
     * key是事件的Class对象,value是订阅者及订阅的方法集合
     */
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    /**
     * 储存订阅者及事件Class对象;
     * 用于判断订阅者是否注册过
     */
    private final Map<Object, List<Class<?>>> typesBySubscriber;
    /**
     * 存储粘性事件;
     * 用于postSticky()
     */
    private final Map<Class<?>, Object> stickyEvents;

    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            // 初始化一个PostingThreadState对象
            return new PostingThreadState();
        }
    };

跟EventBus这个类的这几个成员变量有关,这几个集合的作用主要是用来存储,具体什么作用我都解释了,这个订阅方法的核心

把事件和订阅者相关的方法存储在subscriptionsByEventType 里面,因为一个事件可能在很多地方都注册过,最后还有一个粘性事件

sticky的处理,什么是粘性事件,比如这个事件在A页面发送完毕了,一般情况下注册过的地方就会马上接受到这个事件处理掉,

然后打开过注册了这个事件的B页面的时候,是不会再接受到这个事件的,而粘性事件就相反,打开B页面同样会接受到这个事件,

可以看下源码

// sticky默认false
        if (subscriberMethod.sticky) {
            // eventInheritance 默认为true
            // 如果eventType代表的类或者接口是candidateEventType代表的类或者接口或者父类父接口,也要post事件
            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);
            }
        }
    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, isMainThread());
        }
    }


这里才刚开始注册事件,就调用了postToSubscription()去发布事件,postToSubscription()就是post事件的方法,这个方法后面会讲到,到这里注册就算解析完了,估计客观们都晕了,哈哈,我就用一句话概括下:

注册事件其实就是用一个HashMap   subscriptionsByEventType 把事件和注册了事件相关的类和方法储存起来,方便后面post(事件)使用。


接下来看下post()方法,


    private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>() {
        @Override
        protected PostingThreadState initialValue() {
            // 初始化一个PostingThreadState对象
            return new PostingThreadState();
        }
    };

    /** Posts the given event to the event bus. */
    public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();
        List<Object> eventQueue = postingState.eventQueue;
        // 添加事件event对象
        eventQueue.add(event);

        // 状态是否为posting,如果没有,则开启
        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()) {
                    // 循环开始post事件,每post一个事件,就从eventQueue中移除一个事件对象
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                // 最终恢复默认值
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

TheadLocal不是很清楚的小伙伴可以移步到这,

ThreadLocal源码解析

http://blog.csdn.net/msn465780/article/details/78673656   点击打开链接

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


PostingTheadState是一个静态类内部太监类,说白了就是一个实体,用来存储当前线程和post事件的一些状态。

一开始是存储post的事件,因为可能有很多地方都在post,接下来循环调用postSingleEvent(),

    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        // eventInheritance默认为true
        if (eventInheritance) {
            List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
            int countTypes = eventTypes.size();
            for (int h = 0; h < countTypes; h++) {
                Class<?> clazz = eventTypes.get(h);
                subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
            }
        } else {
            subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
        }
        if (!subscriptionFound) {
            if (logNoSubscriberMessages) {
                // post事件,但是没有地方注册就打印出提示日志
                logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                // 不知道为啥还要执行以下代码,既然没有注册这个事件还去post一个未被注册的新事件,不是形成了递归吗?
                post(new NoSubscriberEvent(this, event));
            }
        }
    }


代码核心是调用postSingleEventForEventType()

    private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            // 从储存regist的方法中获取事件对应的方法
            subscriptions = subscriptionsByEventType.get(eventClass);
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            // 开始循环把同一个事件post到注册者,意思就是调用这个事件订阅的方法
            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;
    }


哈哈,看到了吧,根据事件的Class对象subscriptionsByEventType.get(eventClass) 获取到相关的订阅者和方法,subscriptionsByEventType 还熟悉吗?就是register的时候用来保存的那个HashMap,那到这个方法后干啥呢?调用

postToSubscription(),这个方法还熟悉吗?前面粘性事件Sticky中提到过,就是用的它,是它是它就是它!

    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {
            case POSTING:
                invokeSubscriber(subscription, event);
                break;
            case MAIN:
                if (isMainThread) {
                    // 如果post()在主线程,则立即反射调用订阅方法
                    invokeSubscriber(subscription, event);
                } else {
                    // 否认,加入UI线程消息队列末尾
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case MAIN_ORDERED:
                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) {
                    // 如果post()的线程为UI线程,则在线程池中反射调用订阅方法
                    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);
        }
    }

switch语句根据订阅方法的时候,注解中指定线程,分别post事件,一个一个的讲下为啥这么区分,先看下都用到的方法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);
        }
    }


订阅方法的Method对象调用invoke(),是一种反射机制,参数中知道了订阅者对象,订阅者方法的事件参数对象,那么就可以直接调用到这个订阅方法了,也就达到发送事件接受到事件的循环了。


POSTING 

未指定订阅方法线程的时候默认值,直接调用,post在哪个线程,这个订阅方法就在哪个线程


MAIN           

指定订阅方法在UI线程中执行,如果当前为UI线程直接调用,否则利用MainThreadSupport对象加入UI线程消息队列                               末尾执行,MainThreadSupport其实就是主线程的Handler对象,后面再讲


MAIN_ORDERED   

这个和MAIN有啥区别呢?其实区别就是如果MainThreadSupport存在会优先加入UI线程消息队列末尾,否则才是立即执行


BACKGROUND

如果当前为主线程,加入后台线程执行,否则立即执行


ASYNC

不管当前什么线程,都在后台执行


post主干逻辑基本都说完了,再说下刚才那几个poster,MainThreadSupport、BackgroundPoster、AsyncPoster

他们都是接口,继承于Poster。


MainThreadSupport

public class HandlerPoster extends Handler implements Poster {

    private final PendingPostQueue queue;
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    private boolean handlerActive;

    protected HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);
        this.eventBus = eventBus;
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
        // 创建一个自定义的队列
        queue = new PendingPostQueue();
    }

    public void enqueue(Subscription subscription, Object event) {

        // 获取存储pendingPost  list中最末一个
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            // 获取到的pendingPost 入队
            queue.enqueue(pendingPost);
            // 当前handler对象是否还活动,如果没有活动就让它活动起来,这里的代码就相当于启动handler的作用
            // 让handler处于发送、接受消息的循环中
            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
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            // 如果获取了两次都是null,那么handlerActive = false;跳出方法
                            handlerActive = false;
                            return;
                        }
                    }
                }
                // 通过反射调用订阅者对象的订阅方法
                eventBus.invokeSubscriber(pendingPost);
                // 计算反射调用这个订阅方法的执行耗费时间(毫秒)
                long timeInMethod = SystemClock.uptimeMillis() - started;
                // 默认最大调用时间间隔是10毫秒,如果小于就继续循环从队列中取订阅方法反射调用,
                // 如果大于就把剩下需要调用的加入消息队列末尾,然后又来执行handleMessage(),
                // 因为这是在UI线程中进行的,如果调用时间过长,很容易出现ANR,所以把剩下没
                // 调用完的加入消息队列末尾,让UI的其他操作先执行,防止阻塞
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    // 因为已经加入了队列末尾,所有这个方法没有作用了可以退出去了
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
}

作用就是把post加入到UI线程消息队列末尾执行


BackgroundPoster

final class BackgroundPoster implements Runnable, Poster {

    private final PendingPostQueue queue;
    private final EventBus eventBus;

    private volatile boolean executorRunning;

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

    public void enqueue(Subscription subscription, Object event) {
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            // 线程池是否活跃中,如果没有,则开启
            if (!executorRunning) {
                executorRunning = true;
                // 把当前BackgroundPoster对象放入线程池中并执行
                eventBus.getExecutorService().execute(this);
            }
        }
    }

    @Override
    public void run() {
        try {
            try {
                while (true) {
                    // 从PendingPostQueue中取头部PendingPost,如果取两次都为null,退出方法
                    PendingPost pendingPost = queue.poll(1000);
                    if (pendingPost == null) {
                        synchronized (this) {
                            // Check again, this time in synchronized
                            pendingPost = queue.poll();
                            if (pendingPost == null) {
                                executorRunning = false;
                                return;
                            }
                        }
                    }
                    // 利用反射调用订阅方法
                    eventBus.invokeSubscriber(pendingPost);
                }
            } catch (InterruptedException e) {
                eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
            }
        } finally {
            executorRunning = false;
        }
    }

}


创建了一个线程池,然后在后台中执行


AsyncPoster

class AsyncPoster implements Runnable, Poster {

    private final PendingPostQueue queue;
    private final EventBus eventBus;

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

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

    @Override
    public void run() {
        PendingPost pendingPost = queue.poll();
        if(pendingPost == null) {
            throw new IllegalStateException("No pending post available");
        }
        eventBus.invokeSubscriber(pendingPost);
    }

}

跟BackgroundPoster相似


接下来看下注销事件


我们安卓中一般都会在Activity或者Fragment注册事件,如果不注销肯定会发生内存泄漏,导致内存溢出,

unregister()


    /**
     * 储存事件及对应方法;
     * key是事件的Class对象,value是订阅者及订阅的方法集合
     */
    private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;
    /**
     * 储存订阅者及事件Class对象;
     * 用于判断订阅者是否注册过
     */
    private final Map<Object, List<Class<?>>> typesBySubscriber;

    /** Unregisters the given subscriber from all event classes. */
    public synchronized void unregister(Object subscriber) {
        List<Class<?>> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class<?> eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            typesBySubscriber.remove(subscriber);
        } else {
            logger.log(Level.WARNING, "Subscriber to unregister was not registered before: " + subscriber.getClass());
        }
    }
    /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
    private void unsubscribeByEventType(Object subscriber, Class<?> eventType) {
        List<Subscription> 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;
                    subscriptions.remove(i);
                    i--;
                    size--;
                }
            }
        }
    }

其实我都不用解析了,还记得开始我提到过EventBus有几个成员变量,都是容器类,typesBySubscriber用于判断是否注册过,

subscriptionsByEventType这个很多地方都出现过,保存事件及对应订阅方法的,注销其实就是把这个订阅者和相关方法移除掉,

哈哈,是不是想到判断当前是否注册过的那个方法了,看下源码

    public synchronized boolean isRegistered(Object subscriber) {
        return typesBySubscriber.containsKey(subscriber);
    }


明白了吧!


到这里EventBus这个优秀的框架主干都解析完了,我可能很多地方没描述清楚,不过小伙伴们懂逻辑原理就行了,细微的方法可以下面慢慢看下了。


EventBus说白了就是根据注解把相关的方法都保存在一个HashMap里面,key为事件Class对象,value为订阅者及相关订阅方法的集合,发送事件的时候就根据这个事件的Class对象从HashMap中拿出来一个一个循环的反射调用订阅者的订阅方法。


好了,又可以愉快玩耍了大笑
































猜你喜欢

转载自blog.csdn.net/msn465780/article/details/78710308