EventBus3.0源码详解

原理

先上代码:

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

从代码可以看出,EventBus能够在不同组件、Activity之间通信都是通过一个static的单例对象。是观察者模式的一种应用,注册—>list.add post—>通知所有注册的观察者。具体来看代码。

注册

先来看register方法:

 public void register(Object subscriber) {
        Class<?> subscriberClass = subscriber.getClass(); //获取观察者的Class
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); //获取Class中带有Subscribe注释的方法
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);//核心代码,下面会详细分析
            }
        }
    }

在register方法中调用的subscribe方法:

private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class<?> eventType = subscriberMethod.eventType; //注册的方法所在的class
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);//此对象是用来检测是否已经调用过注册
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);//全局的Map中获取所有此class注册的方法
        if (subscriptions == null) {//观察者第一次调用注册(观察者class中有多个subscribe方法会调用多次)
            subscriptions = new CopyOnWriteArrayList<>();
            subscriptionsByEventType.put(eventType, subscriptions);//将注册对象的class和class中的注册方法放入全局Map中
        } else {
            if (subscriptions.contains(newSubscription)) {//此类型的Event已经在class上注册过了,抛出异常
                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) {//检查优先级 优先级高的在前  默认优先级为0 可通过在观察中用    priority = X 来配置
                subscriptions.add(i, newSubscription);
                break;
            }
        }

        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {//第一次调用-->新建key--value配对
            subscribedEvents = new ArrayList<>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);

        if (subscriberMethod.sticky) { //是否是sticky事件(如果是粘性事件,事件总线会传递最近的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);
            }
        }
    }

上面一段代码中用到的几个成员变量:

private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;//存观察者的class和对应的SubcriptionList

private final Map<Object, List<Class<?>>> typesBySubscriber;//存观察者和观察者需要观察的数据类型List

以上为EventBus的注册过程,代码中涉及的其他类后面会详细分析,这里只是分析流程。

Post事件

EventBus为Post事件提供了两个方法post()和postSticky(),其中postSticky()内部也是通过post()实现的只不过是多了事件的保存,代码如下:

 /**
     * Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky
     * event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}.
     */
    public void postSticky(Object event) {
        synchronized (stickyEvents) {
            stickyEvents.put(event.getClass(), event);
        }
        // Should be posted after it is putted, in case the subscriber wants to remove immediately
        post(event);
    }

这里注释已经解释的很明显了"将给定的事件发布到事件总线并保持事件(因为它是粘性的)。事件类型的最新粘性事件保存在内存中,供使用{@link Subscribe#sticky()}的订阅者将来访问。"
再来看post:

/** Posts the given event to the event bus. */
    public void post(Object event) {
        PostingThreadState postingState = currentPostingThreadState.get();//获取post线程的状态,这里currentPostingThreadState被ThreadLocal修饰只能在一个线程中访问
        List<Object> eventQueue = postingState.eventQueue;//获取待post的数据队列
        eventQueue.add(event);

        if (!postingState.isPosting) {
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();//判断post线程是否是主线程
            postingState.isPosting = true;//更新Post状态
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                while (!eventQueue.isEmpty()) {//依次向观察者发送事件,直到队列为空
                    postSingleEvent(eventQueue.remove(0), postingState);//核心代码,下面会详细分析
                }
            } finally {
         	   //重置post状态
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }

post()方法中调用的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) { //未找到观察者-->post一个NoSubscriberEvent
            if (logNoSubscriberMessages) {
                Log.d(TAG, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                post(new NoSubscriberEvent(this, event));
            }
        }
    }

再来看postSingleEventForEventType():

private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
        CopyOnWriteArrayList<Subscription> subscriptions;
        synchronized (this) {
            subscriptions = subscriptionsByEventType.get(eventClass);//获取class的subcriptions
        }
        if (subscriptions != null && !subscriptions.isEmpty()) {
            for (Subscription subscription : subscriptions) {//通知对应的观察者执行对应的方法
                postingState.event = event;
                postingState.subscription = subscription;
                boolean aborted = false;//定义post中止标志
                try {
                    postToSubscription(subscription, event, postingState.isMainThread);//核心代码,下面分析
                    aborted = postingState.canceled;
                } finally {//更新post状态
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                if (aborted) {//post中止跳出循环不再post事件,返回true
                    break;
                }
            }
            return true;
        }
        return false;
    }

再来看postToSubscription():

private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        switch (subscription.subscriberMethod.threadMode) {//switch观察者方法执行的线程 --- 默认和post为同一个线程
            case POSTING://post数据线程
                invokeSubscriber(subscription, event); //通过反射调用对应方法,下面详解
                break;
            case MAIN://主线程
                if (isMainThread) {//post线程是否是主线程
                    invokeSubscriber(subscription, event);//如果是主线程,直接通过反射调用对应方法
                } else {//不是主线程
                    mainThreadPoster.enqueue(subscription, event);//通知处理主线程事件的HandlerPoster(HandlerPoster内部有一个队列,此处实际上是往队列中添加一条数据)
                }
                break;
            case BACKGROUND://后台(如果post线程不是主线程,将在post线程中调用)  以下代码调用流程同上一个case
                if (isMainThread) {
                    backgroundPoster.enqueue(subscription, event);
                } else {
                    invokeSubscriber(subscription, event);
                }
                break;
            case ASYNC://独立于post线程和主线程  无需判断post线程直接通过处理ASYNC事件的HandlerPoster处理
                asyncPoster.enqueue(subscription, event);
                break;
            default://抛出异常
                throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.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);
        }
    }

相关类分析

Subscription

代码中多次使用到Subcription对象,构造其实也很简单,用来绑定观察者和subcribe方法,代码如下:

final class Subscription {
    final Object subscriber;
    final SubscriberMethod subscriberMethod;
    /**
     * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery
     * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions.
     */
    volatile boolean active;//是否活动  源码注释很详细"当unregister()被调用后会置为false,通过队列事件传递进行检查”

    Subscription(Object subscriber, SubscriberMethod subscriberMethod) {
        this.subscriber = subscriber;
        this.subscriberMethod = subscriberMethod;
        active = true;
    }

    @Override
    public boolean equals(Object other) {//重写equals方法
        if (other instanceof Subscription) {
            Subscription otherSubscription = (Subscription) other;
            return subscriber == otherSubscription.subscriber
                    && subscriberMethod.equals(otherSubscription.subscriberMethod);//如果观察者和subscribe方法都一样的话认为是同一个Subscription对象
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return subscriber.hashCode() + subscriberMethod.methodString.hashCode();
    }
}

SubscriberMethod

public class SubscriberMethod {
    final Method method;//方法体	
    final ThreadMode threadMode;//方法执行线程
    final Class<?> eventType;//执行method的class
    final int priority;//优先级
    final boolean sticky;//是否是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;
    }

    @Override
    public boolean equals(Object other) {
        if (other == this) {
            return true;
        } else if (other instanceof SubscriberMethod) {
            checkMethodString();
            SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other;
            otherSubscriberMethod.checkMethodString();
            // Don't use method.equals because of http://code.google.com/p/android/issues/detail?id=7811#c6
            return methodString.equals(otherSubscriberMethod.methodString);
        } else {
            return false;
        }
    }

    private synchronized void checkMethodString() {
        if (methodString == null) {
            // Method.toString has more overhead, just take relevant parts of the method
            StringBuilder builder = new StringBuilder(64);
            builder.append(method.getDeclaringClass().getName());
            builder.append('#').append(method.getName());
            builder.append('(').append(eventType.getName());
            methodString = builder.toString();
        }
    }

    @Override
    public int hashCode() {
        return method.hashCode();
    }
}

HandlerPoster

将post线程不在主线程的事件发送到主线程处理的Handler

final class HandlerPoster extends Handler {

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

BackgroundPoster

EventBus 内部有维护一个Executors.newCachedThreadPool 的线程池,当调用 BackGroudPost.enqueue 的时候,会将事件弄到线程池中执行。 BackGroundPost是一个 Runnable, 内部维护一个队列,在 run 方法中会不断的从队列中取出 PendingPost,当队列没有事件时,至多等待1s,然后跳出 run 方法。

final class BackgroundPoster implements Runnable {
    private final PendingPostQueue queue;
    private final EventBus eventBus;

    private volatile boolean executorRunning;
}

AsyncPoster

AsyncPoster 的实现跟 BackgroundPoster 的实现极为类似,区别就是是否有在 run 方法中循环取出 PendingPost。 主要的不同点就是,AsyncPost 会确保每一个任务都会在不同的线程中执行,而 BackgroundPoster 则如果发送的速度比较快且接收事件都是在 background 中,则会在同一线程中执行。

class AsyncPoster implements Runnable {

    private final PendingPostQueue queue;
    private final EventBus eventBus;
}

至此,关于EventBus3.0的代码原理分析的差不多了,当然很多细节不够详细,也还有很多相关方法没有分析到,个人认为不必太纠结于细节,分析开源框架主要是要学习思想不是么?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值