Android EventBus3.0源码分析

在我们开发过程中,相信应该有很多人使用过EventBus 3.0,这个确实方便了我们,少些了很多代码,这是个优秀的库,我们接下来进行对他剖析。
我们使用EventBus 3.0的过程:

EventBus.getDefault().register()
EventBus.getDefault().post()
EventBus.getDefault().unregister()

我们先看看是怎么初始化的

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

 /**
     * Creates a new EventBus instance; each instance is a separate scope in which events are delivered. To use a
     * central bus, consider {@link #getDefault()}.
     */
    public EventBus() {
        this(DEFAULT_BUILDER);
    }
  
  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;
    }

一个单例模式,接着点你会发现其实是利用的Builder模式,而框架内部帮我们写了一个EventBusBuilder

private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();

 EventBusBuilder() {

  }

EventBusBuilder初始化的时候除了对成员变量的一些初始化外,其他的并没有做什么操作。
接下来我们进入register函数

/**
     * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they
     * are no longer interested in receiving events.
     * 

* 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(); //根据subscriberClass 获取订阅的方法 List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); synchronized (this) { //遍历订阅 for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } } }

从这个函数我们可以很清晰的看到逻辑,首先根据subscriber(Activity,Fragment)得到相应的订阅方法,然后在遍历订阅。这里代码就不点进去看了,主要说下框架的实现思路。

采用了缓存加反射的方式,主要的参数和类为下:
METHOD_CACHE:一个key为订阅者classvalue为需要订阅实现的方法的一个ConcurrentHashMap,这个HashMap是为了保证线程并发安全。我们获取的订阅方法就会缓存到这里面。
FindState:顾名思义,这是一个检测状态的类,里面的参数为

 final List subscriberMethods = new ArrayList<>();
        final Map anyMethodByEventType = new HashMap<>();
        final Map subscriberClassByMethodKey = new HashMap<>();
        final StringBuilder methodKeyBuilder = new StringBuilder(128);

        Class subscriberClass;
        Class clazz;
        boolean skipSuperClasses;
        SubscriberInfo subscriberInfo;

里面比较重要的几个参数:
SubscriberMethod: 当前订阅对象(Activity,Fragment)的订阅方法实体。

public class SubscriberMethod {
    //方法
    final Method method;
//模式
    final ThreadMode threadMode;
//类型, 就是参数的类型   参数只能为1个
    final Class eventType;
    final int priority;
    final boolean sticky;
    /** Used for efficient comparison */
    String methodString;

subscriberMethods:用来存储当前订阅对象(Activity,Fragment)内的订阅方法SubscriberMethod
anyMethodByEventType: key为参数类型(订阅类型),value为方法的一个缓存。
subscriberClassByMethodKey:key订阅方法名+">"+参数类型name,value为订阅方法的class

获取订阅方法的时候先判断缓存里面是否存在,不存在就获取FindState实例,根据反射获取注解Subscribe(Activity,Fragment)的方法,然后对FindState实例进行操作(anyMethodByEventTypesubscriberClassByMethodKey得到相应的值或添加到缓存),获取到的订阅方法集合其实就是FindState实例里面的subscriberMethods,最后在把获取的订阅方法集合加入缓存。
得到了订阅方法集合接下来就遍历subscriberMethods

private final Map, CopyOnWriteArrayList> subscriptionsByEventType;
private final Map>> typesBySubscriber;
 private final Map, Object> stickyEvents;


 // Must be called in synchronized block
    private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
        Class eventType = subscriberMethod.eventType;
        Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
        CopyOnWriteArrayList 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();
        for (int i = 0; i <= size; i++) {
            if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                subscriptions.add(i, newSubscription);
                break;
            }
        }

        List> subscribedEvents = typesBySubscriber.get(subscriber);
        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).
                Set, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry, 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);
            }
        }
    }

订阅的时候,首先根据订阅者(Activity Fragment)SubscriberMethod得到一个Subscription对象,这个类就是一个真正执行信息传递的订阅对象。

/*
 * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.greenrobot.eventbus;

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;

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

    @Override
    public boolean equals(Object other) {
        if (other instanceof Subscription) {
            Subscription otherSubscription = (Subscription) other;
            return subscriber == otherSubscription.subscriber
                    && subscriberMethod.equals(otherSubscription.subscriberMethod);
        } else {
            return false;
        }
    }

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

接着把这个Subscription对象添加CopyOnWriteArrayListCopyOnWriteArrayList是一个适合用在读多,写少并发应用中,它是一个线程安全的集合)然后将这个CopyOnWriteArrayList添加到subscriptionsByEventType里面,这个subscriptionsByEventType是一个key为订阅方法的类型(方法函数的类型),value为一个存放SubscriptionCopyOnWriteArrayListHashMap。接下来把订阅方法的类型(参数类型)eventType添加到一个ArrayList里面,在将这个ArrayList添加到typesBySubscribertypesBySubscriber是一个key为订阅者对象(Fragment,Activity),valueArrayList>HashMap,最后在判断是否是sticky,如果是的就将遍历一个stickyEventsHashMap,然后根据key(订阅方法类型)发出消息。

我们看看unregister

 /** Unregisters the given subscriber from all event classes. */
    public synchronized void unregister(Object subscriber) {
        List> subscribedTypes = typesBySubscriber.get(subscriber);
        if (subscribedTypes != null) {
            for (Class eventType : subscribedTypes) {
                unsubscribeByEventType(subscriber, eventType);
            }
            typesBySubscriber.remove(subscriber);
        } else {
            Log.w(TAG, "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 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--;
                }
            }
        }
    }

很简单,先根据订阅者(Activity Fragment)获取到typesBySubscriber里面的订阅方法类型集合(List> subscribedTypes),然后遍历这个集合,根据这个订阅方法类型得到subscriptionsByEventType里面的订阅对象集合List subscriptions,在遍历这个subscriptions集合,判断subscription.subscriber == subscriber然后移除,最后在移除typesBySubscriber里面的这个订阅对象(Fragment ,Activity )

接下来我们看看post,最终会走到这个函数

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 {
                    mainThreadPoster.enqueue(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);
        }
    }


/**
     * Invokes the subscriber if the subscriptions is still active. Skipping subscriptions prevents race conditions
     * between {@link #unregister(Object)} and event delivery. Otherwise the event might be delivered after the
     * subscriber unregistered. This is particularly important for main thread delivery and registrations bound to the
     * live cycle of an Activity or Fragment.
     */
    void invokeSubscriber(PendingPost pendingPost) {
        Object event = pendingPost.event;
        Subscription subscription = pendingPost.subscription;
        PendingPost.releasePendingPost(pendingPost);
        if (subscription.active) {
            invokeSubscriber(subscription, event);
        }
    }

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

在发送消息的时候根据消息类型(参数类型)然后从上面的subscriptionsByEventType里面取出相应的数据进行封装成一个PendingPost对象,在根据反射invoke对应的方法即可,如果是MAIN的话就通过Handler进行线程转换,如果是BACKGROUND并且是在主线程中调用或者是ASYNC将会通过线程池来进行线程切换。

接下来看看postSticky

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

这个其实我们在注册的时候已经分析了,当调用这个函数的时候,将会将这个消息加到stickyEvents里面,这个stickyEvents是一个ConcurrentHashMap,ConcurrentHashMap是一个应用于高并发的键值对,接着调用post函数先把已经注册的观察者的方法实现,接下来其他对象注册的时候

 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).
                Set, Object>> entries = stickyEvents.entrySet();
                for (Map.Entry, 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);
            }
        }

在这里将会调用。
还有一个优先级priority问题,可以看到也是在注册的时候

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

其实也是很简单的原理。源码分析得也差不多了,具体的需要大家自己去查看源码。

总结,EventBus的实现方式:反射 + 数据封装 + 缓存 + 线程切换
通过查看EventBus的源码收获了什么?

  1. Builder模式封装参数
  1. 根据用处不同进行对不同的类封装,比如:SubscriberMethodFinder用于订阅方法的查找;FindState一个用SubscriberMethodFinder查找的辅助类,里面封装了一些数据;SubscriberMethod订阅方法实体,就是通过注解的方法对应的对象;Subscription一个订阅对象。
  2. 缓存
  3. 线程切换使用方式
  4. 反射用法熟悉加强
  5. ThreadLocal是一个关于创建线程局部变量的类。
    通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。而使用ThreadLocal创建的变量只能被当前线程访问,其他线程则无法访问和修改。
  6. CopyOnWriteArrayList:是一个适合用在读多,写少的并发应用中,它是一个线程安全的集合
  7. ConcurrentHashMap:是一个应用于高并发的键值对

人生苦短,要学会享受!但是我还没到应该安于享受的年龄!

你可能感兴趣的:(Android EventBus3.0源码分析)