美文网首页Android知识
Android事件总线 EventBus 2.4 源码分析

Android事件总线 EventBus 2.4 源码分析

作者: MarkZhai | 来源:发表于2016-02-05 14:29 被阅读300次

    EventBus简介

    本篇基于EventBus 2.4撰写。

    Android optimized event bus that simplifies communication between Activities, Fragments, Threads, Services, etc. Less code, better quality.

    上面是从官方repo拉来的代码,大致是说简化的组件之间的交流通信,减少代码,提高质量。

    其实和EventBus最早是在qzone的代码里认识的,空间内部有一个叫eventcenter的东西,曾经有优化过一些,当时看源码实现的时候发现的原来是根据EventBus改的一个实现。大概就是把annotation的实现改成了接口实现,另外去掉了根据Event类型来找订阅者的模式,完全通过Event的TYPE类型常量来判断,register的时候直接指定对哪种TYPE感兴趣,辅助的判断则有事件发送者引用。这种实现见仁见智吧,虽然直接通过接口肯定是能提高性能的。这里要吐槽的是实现修改的时候,直接把很多对外的接口名字改掉了,何必呢。

    EventBus的好处是显而易见的,完全解耦了请求链之间的关系,避免了请求者被长持有,又比广播更轻量,比LocalBroadcast则更强大,接口也简单实用。缺点的话,像是各种Event的定义是一个工作量。

    源码分析 - 注册(register)

    EventBus.java:

    private synchronized void register(Object subscriber, boolean sticky, int priority) {
        List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass());
        for (SubscriberMethod subscriberMethod : subscriberMethods) {
            subscribe(subscriber, subscriberMethod, sticky, priority);
        }
    }
    

    register的时候,大致就是去subscriber里面首先找到那些onEvent方法(目前实现仍然是根据onEvent这个前缀),寻找的时候会去判断后缀,分为post线程、主线程、background线程,以及异步线程,官方repo提到这里之后在3.0可能会换成annotation的实现。

    sticky参数是粘性事件概念,postSticky和registerSticky相对应,stickyEvent会记录该EventType对应的最后一次postSticky的事件,这样在registerSticky的时候,会立即检查是否有之前post的事件,从而避免了某些事件去实现自己的缓存。应用场景大概就是某些activity/fragment感兴趣的事件发生在创建前,这样则可以避免必须实现缓存(当然事实上应用场景还是比较少的,因为大部分东西我们还是会在哪里记录一下)

    SubscriberMethod.java:

    final class SubscriberMethod {
        final Method method;
        final ThreadMode threadMode;
        final Class<?> eventType;
        /** Used for efficient comparison */
        String methodString;
    }
    

    SubscriberMethod里面记录了Method引用,线程模式(在findSubscriberMethods里拿到的),eventType,以及用来提高method.equals性能的methodString。

    接着再看subscribe方法的实现,在register最后,对找到的所有方法都去执行了一遍subscribe
    EventBus.java:

    // Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) {
        Class<?> eventType = subscriberMethod.eventType;
    
        // CopyOnWriteArrayList就是个ImmutableArrayList, add/set等方法会返回一个新的ArrayList
        // subscriptionsByEventType是一个hashmap,key是事件类型,value则是订阅者数组
        CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
    
    
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority);
    
        // 该eventType在map里还不存在,新建一下对应的subscription数组,放进去map
        if (subscriptions == null) {
            subscriptions = new CopyOnWriteArrayList<Subscription>();
            subscriptionsByEventType.put(eventType, subscriptions);
        } else {
            // 重复注册的时候抛出异常,这里如果应用如果觉得无伤大雅其实可以直接return
            if (subscriptions.contains(newSubscription)) {
                throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                        + eventType);
            }
        }
    
        // 根据优先级去添加到对应的位置,高优先级在前面也就会先处理
        int size = subscriptions.size();
        for (int i = 0; i <= size; i++) {
            if (i == size || newSubscription.priority > subscriptions.get(i).priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }
    
        // typesBySubscriber是另一个map,顾名思义是以subscriber为key的一个map,被用在
        // 1) isRegistered(Object subscriber)方法加速判断是否已注册,用空间换时间
        // 2) unregister的时候直接可以拿到subscriber订阅的所有eventType,然后去从map移除,避免需要遍历所有eventType的map
        List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
        if (subscribedEvents == null) {
            subscribedEvents = new ArrayList<Class<?>>();
            typesBySubscriber.put(subscriber, subscribedEvents);
        }
        subscribedEvents.add(eventType);
    
        // 粘性事件的话,就去立刻找一下是否有之前post过的事件,有则立即post给该subscriber
        if (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);
            }
        }
    }
    

    源码分析 - 发送事件(post)

    再来看一下对应的post逻辑

    EventBus.java:

    /** Posts the given event to the event bus. */
    public void post(Object event) {
        // 获得当前post线程的状态,实现贴在下面了,currentPostingThreadState是ThreadLocal<PostingThreadState>变量,每个线程get和set的都是单独的一份数据
        PostingThreadState postingState = currentPostingThreadState.get();
        // 往事件队列里面添加该event
        List<Object> eventQueue = postingState.eventQueue;
        eventQueue.add(event);
    
        // 如果当前不在posting事件
        if (!postingState.isPosting) {
            // 设置是否在主线程
            postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
            // 设置当前正在post事件
            postingState.isPosting = true;
            // canceled状态,抛出异常
            if (postingState.canceled) {
                throw new EventBusException("Internal error. Abort state was not reset");
            }
            try {
                // 循环post从eventQueue里面拿出来的event
                while (!eventQueue.isEmpty()) {
                    postSingleEvent(eventQueue.remove(0), postingState);
                }
            } finally {
                // 置位回去
                postingState.isPosting = false;
                postingState.isMainThread = false;
            }
        }
    }
    
    final static class PostingThreadState {
        final List<Object> eventQueue = new ArrayList<Object>();
        boolean isPosting;
        boolean isMainThread;
        Subscription subscription;
        Object event;
        // 可以通过cancelEventDelivery去取消事件传递
        boolean canceled;
    }
    
    // 单个事件的post处理
    private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
        Class<?> eventClass = event.getClass();
        boolean subscriptionFound = false;
        // 继承链处理,比如Event本身的父类的subscriber也会收到,getDefault的时候默认为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) {
                Log.d(TAG, "No subscribers registered for event " + eventClass);
            }
            if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                    eventClass != SubscriberExceptionEvent.class) {
                // 没想到还有这种逻辑吧,没找到订阅者的,则会发送一个NoSubscriberEvent出去
                post(new NoSubscriberEvent(this, event));
            }
        }
    }
    
    // 对特定的event去post单个事件
    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 {
                    // 结果实际post还在这个方法内实现
                    postToSubscription(subscription, event, postingState.isMainThread);
                    aborted = postingState.canceled;
                } finally {
                    postingState.event = null;
                    postingState.subscription = null;
                    postingState.canceled = false;
                }
                // 如果cancel了,则不再继续传递事件
                if (aborted) {
                    break;
                }
            }
            return true;
        }
        return false;
    }
    
    // 具体的事件分发
    private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
        // 这里就是EventBus的一个很强大的功能了,根据订阅者的订阅方法监听线程去处理
        // 如果post和监听方法在同一个线程则立即invoke对应方法
        // 否则会去入队列到对应线程handler进行处理
        switch (subscription.subscriberMethod.threadMode) {
            case PostThread:
                invokeSubscriber(subscription, event);
                break;
            case MainThread:
                if (isMainThread) {
                    invokeSubscriber(subscription, event);
                } else {
                    mainThreadPoster.enqueue(subscription, event);
                }
                break;
            case BackgroundThread:
                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);
        }
    }
    

    End

    大致就讲了一下register和post这一对比较常用的接口,其他还有一些实现像是EventBusBuilder,SubscriberException,cancelEventDelivery,AsyncExecutor就不在这里进行赘述,之后可能会对AsyncExecutor单独开一篇讲一下,另外也会对otto的实现做一下分析。

    原文见:http://blog.zhaiyifan.cn/2015/08/20/EventBus%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/

    相关文章

      网友评论

        本文标题:Android事件总线 EventBus 2.4 源码分析

        本文链接:https://www.haomeiwen.com/subject/qhzekttx.html